Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/common.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/conftest.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_alter_axes.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_api.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_arrow_interface.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_block_internals.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_cumulative.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_iteration.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_logical_ops.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_nonunique_indexes.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_npfuncs.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_query_eval.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_repr.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_subclass.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_ufunc.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_unary.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_validate.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/constructors/__init__.py +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/constructors/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/constructors/__pycache__/test_from_dict.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/constructors/__pycache__/test_from_records.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/constructors/test_from_dict.py +228 -0
- lib/python3.12/site-packages/pandas/tests/frame/constructors/test_from_records.py +505 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/__init__.py +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/__init__.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_coercion.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_delitem.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_get.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_get_value.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_getitem.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_insert.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_mask.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_set_value.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_setitem.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_take.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_where.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_xs.cpython-312.pyc +0 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/test_coercion.py +199 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/test_delitem.py +60 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/test_get.py +27 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/test_get_value.py +22 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/test_getitem.py +472 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/test_indexing.py +2024 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/test_insert.py +120 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/test_mask.py +152 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/test_set_value.py +77 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/test_setitem.py +1419 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/test_take.py +92 -0
- lib/python3.12/site-packages/pandas/tests/frame/indexing/test_where.py +1099 -0
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (197 Bytes). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/common.cpython-312.pyc
ADDED
|
Binary file (3.24 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/conftest.cpython-312.pyc
ADDED
|
Binary file (4.5 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_alter_axes.cpython-312.pyc
ADDED
|
Binary file (1.67 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_api.cpython-312.pyc
ADDED
|
Binary file (21.8 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_arrow_interface.cpython-312.pyc
ADDED
|
Binary file (2.78 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_block_internals.cpython-312.pyc
ADDED
|
Binary file (22.9 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_cumulative.cpython-312.pyc
ADDED
|
Binary file (4.37 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_iteration.cpython-312.pyc
ADDED
|
Binary file (9.34 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_logical_ops.cpython-312.pyc
ADDED
|
Binary file (10.2 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_nonunique_indexes.cpython-312.pyc
ADDED
|
Binary file (16.6 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_npfuncs.cpython-312.pyc
ADDED
|
Binary file (4.4 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_query_eval.cpython-312.pyc
ADDED
|
Binary file (90.1 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_repr.cpython-312.pyc
ADDED
|
Binary file (27.3 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_subclass.cpython-312.pyc
ADDED
|
Binary file (43.1 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_ufunc.cpython-312.pyc
ADDED
|
Binary file (18.1 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_unary.cpython-312.pyc
ADDED
|
Binary file (11 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/__pycache__/test_validate.cpython-312.pyc
ADDED
|
Binary file (1.88 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/constructors/__init__.py
ADDED
|
File without changes
|
lib/python3.12/site-packages/pandas/tests/frame/constructors/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (210 Bytes). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/constructors/__pycache__/test_from_dict.cpython-312.pyc
ADDED
|
Binary file (11.6 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/constructors/__pycache__/test_from_records.cpython-312.pyc
ADDED
|
Binary file (31.2 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/constructors/test_from_dict.py
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from collections import OrderedDict
|
| 2 |
+
|
| 3 |
+
import numpy as np
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from pandas._config import using_pyarrow_string_dtype
|
| 7 |
+
|
| 8 |
+
from pandas import (
|
| 9 |
+
DataFrame,
|
| 10 |
+
Index,
|
| 11 |
+
MultiIndex,
|
| 12 |
+
RangeIndex,
|
| 13 |
+
Series,
|
| 14 |
+
)
|
| 15 |
+
import pandas._testing as tm
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class TestFromDict:
|
| 19 |
+
# Note: these tests are specific to the from_dict method, not for
|
| 20 |
+
# passing dictionaries to DataFrame.__init__
|
| 21 |
+
|
| 22 |
+
def test_constructor_list_of_odicts(self):
|
| 23 |
+
data = [
|
| 24 |
+
OrderedDict([["a", 1.5], ["b", 3], ["c", 4], ["d", 6]]),
|
| 25 |
+
OrderedDict([["a", 1.5], ["b", 3], ["d", 6]]),
|
| 26 |
+
OrderedDict([["a", 1.5], ["d", 6]]),
|
| 27 |
+
OrderedDict(),
|
| 28 |
+
OrderedDict([["a", 1.5], ["b", 3], ["c", 4]]),
|
| 29 |
+
OrderedDict([["b", 3], ["c", 4], ["d", 6]]),
|
| 30 |
+
]
|
| 31 |
+
|
| 32 |
+
result = DataFrame(data)
|
| 33 |
+
expected = DataFrame.from_dict(
|
| 34 |
+
dict(zip(range(len(data)), data)), orient="index"
|
| 35 |
+
)
|
| 36 |
+
tm.assert_frame_equal(result, expected.reindex(result.index))
|
| 37 |
+
|
| 38 |
+
def test_constructor_single_row(self):
|
| 39 |
+
data = [OrderedDict([["a", 1.5], ["b", 3], ["c", 4], ["d", 6]])]
|
| 40 |
+
|
| 41 |
+
result = DataFrame(data)
|
| 42 |
+
expected = DataFrame.from_dict(dict(zip([0], data)), orient="index").reindex(
|
| 43 |
+
result.index
|
| 44 |
+
)
|
| 45 |
+
tm.assert_frame_equal(result, expected)
|
| 46 |
+
|
| 47 |
+
@pytest.mark.skipif(
|
| 48 |
+
using_pyarrow_string_dtype(), reason="columns inferring logic broken"
|
| 49 |
+
)
|
| 50 |
+
def test_constructor_list_of_series(self):
|
| 51 |
+
data = [
|
| 52 |
+
OrderedDict([["a", 1.5], ["b", 3.0], ["c", 4.0]]),
|
| 53 |
+
OrderedDict([["a", 1.5], ["b", 3.0], ["c", 6.0]]),
|
| 54 |
+
]
|
| 55 |
+
sdict = OrderedDict(zip(["x", "y"], data))
|
| 56 |
+
idx = Index(["a", "b", "c"])
|
| 57 |
+
|
| 58 |
+
# all named
|
| 59 |
+
data2 = [
|
| 60 |
+
Series([1.5, 3, 4], idx, dtype="O", name="x"),
|
| 61 |
+
Series([1.5, 3, 6], idx, name="y"),
|
| 62 |
+
]
|
| 63 |
+
result = DataFrame(data2)
|
| 64 |
+
expected = DataFrame.from_dict(sdict, orient="index")
|
| 65 |
+
tm.assert_frame_equal(result, expected)
|
| 66 |
+
|
| 67 |
+
# some unnamed
|
| 68 |
+
data2 = [
|
| 69 |
+
Series([1.5, 3, 4], idx, dtype="O", name="x"),
|
| 70 |
+
Series([1.5, 3, 6], idx),
|
| 71 |
+
]
|
| 72 |
+
result = DataFrame(data2)
|
| 73 |
+
|
| 74 |
+
sdict = OrderedDict(zip(["x", "Unnamed 0"], data))
|
| 75 |
+
expected = DataFrame.from_dict(sdict, orient="index")
|
| 76 |
+
tm.assert_frame_equal(result, expected)
|
| 77 |
+
|
| 78 |
+
# none named
|
| 79 |
+
data = [
|
| 80 |
+
OrderedDict([["a", 1.5], ["b", 3], ["c", 4], ["d", 6]]),
|
| 81 |
+
OrderedDict([["a", 1.5], ["b", 3], ["d", 6]]),
|
| 82 |
+
OrderedDict([["a", 1.5], ["d", 6]]),
|
| 83 |
+
OrderedDict(),
|
| 84 |
+
OrderedDict([["a", 1.5], ["b", 3], ["c", 4]]),
|
| 85 |
+
OrderedDict([["b", 3], ["c", 4], ["d", 6]]),
|
| 86 |
+
]
|
| 87 |
+
data = [Series(d) for d in data]
|
| 88 |
+
|
| 89 |
+
result = DataFrame(data)
|
| 90 |
+
sdict = OrderedDict(zip(range(len(data)), data))
|
| 91 |
+
expected = DataFrame.from_dict(sdict, orient="index")
|
| 92 |
+
tm.assert_frame_equal(result, expected.reindex(result.index))
|
| 93 |
+
|
| 94 |
+
result2 = DataFrame(data, index=np.arange(6, dtype=np.int64))
|
| 95 |
+
tm.assert_frame_equal(result, result2)
|
| 96 |
+
|
| 97 |
+
result = DataFrame([Series(dtype=object)])
|
| 98 |
+
expected = DataFrame(index=[0])
|
| 99 |
+
tm.assert_frame_equal(result, expected)
|
| 100 |
+
|
| 101 |
+
data = [
|
| 102 |
+
OrderedDict([["a", 1.5], ["b", 3.0], ["c", 4.0]]),
|
| 103 |
+
OrderedDict([["a", 1.5], ["b", 3.0], ["c", 6.0]]),
|
| 104 |
+
]
|
| 105 |
+
sdict = OrderedDict(zip(range(len(data)), data))
|
| 106 |
+
|
| 107 |
+
idx = Index(["a", "b", "c"])
|
| 108 |
+
data2 = [Series([1.5, 3, 4], idx, dtype="O"), Series([1.5, 3, 6], idx)]
|
| 109 |
+
result = DataFrame(data2)
|
| 110 |
+
expected = DataFrame.from_dict(sdict, orient="index")
|
| 111 |
+
tm.assert_frame_equal(result, expected)
|
| 112 |
+
|
| 113 |
+
def test_constructor_orient(self, float_string_frame):
|
| 114 |
+
data_dict = float_string_frame.T._series
|
| 115 |
+
recons = DataFrame.from_dict(data_dict, orient="index")
|
| 116 |
+
expected = float_string_frame.reindex(index=recons.index)
|
| 117 |
+
tm.assert_frame_equal(recons, expected)
|
| 118 |
+
|
| 119 |
+
# dict of sequence
|
| 120 |
+
a = {"hi": [32, 3, 3], "there": [3, 5, 3]}
|
| 121 |
+
rs = DataFrame.from_dict(a, orient="index")
|
| 122 |
+
xp = DataFrame.from_dict(a).T.reindex(list(a.keys()))
|
| 123 |
+
tm.assert_frame_equal(rs, xp)
|
| 124 |
+
|
| 125 |
+
def test_constructor_from_ordered_dict(self):
|
| 126 |
+
# GH#8425
|
| 127 |
+
a = OrderedDict(
|
| 128 |
+
[
|
| 129 |
+
("one", OrderedDict([("col_a", "foo1"), ("col_b", "bar1")])),
|
| 130 |
+
("two", OrderedDict([("col_a", "foo2"), ("col_b", "bar2")])),
|
| 131 |
+
("three", OrderedDict([("col_a", "foo3"), ("col_b", "bar3")])),
|
| 132 |
+
]
|
| 133 |
+
)
|
| 134 |
+
expected = DataFrame.from_dict(a, orient="columns").T
|
| 135 |
+
result = DataFrame.from_dict(a, orient="index")
|
| 136 |
+
tm.assert_frame_equal(result, expected)
|
| 137 |
+
|
| 138 |
+
def test_from_dict_columns_parameter(self):
|
| 139 |
+
# GH#18529
|
| 140 |
+
# Test new columns parameter for from_dict that was added to make
|
| 141 |
+
# from_items(..., orient='index', columns=[...]) easier to replicate
|
| 142 |
+
result = DataFrame.from_dict(
|
| 143 |
+
OrderedDict([("A", [1, 2]), ("B", [4, 5])]),
|
| 144 |
+
orient="index",
|
| 145 |
+
columns=["one", "two"],
|
| 146 |
+
)
|
| 147 |
+
expected = DataFrame([[1, 2], [4, 5]], index=["A", "B"], columns=["one", "two"])
|
| 148 |
+
tm.assert_frame_equal(result, expected)
|
| 149 |
+
|
| 150 |
+
msg = "cannot use columns parameter with orient='columns'"
|
| 151 |
+
with pytest.raises(ValueError, match=msg):
|
| 152 |
+
DataFrame.from_dict(
|
| 153 |
+
{"A": [1, 2], "B": [4, 5]},
|
| 154 |
+
orient="columns",
|
| 155 |
+
columns=["one", "two"],
|
| 156 |
+
)
|
| 157 |
+
with pytest.raises(ValueError, match=msg):
|
| 158 |
+
DataFrame.from_dict({"A": [1, 2], "B": [4, 5]}, columns=["one", "two"])
|
| 159 |
+
|
| 160 |
+
@pytest.mark.parametrize(
|
| 161 |
+
"data_dict, orient, expected",
|
| 162 |
+
[
|
| 163 |
+
({}, "index", RangeIndex(0)),
|
| 164 |
+
(
|
| 165 |
+
[{("a",): 1}, {("a",): 2}],
|
| 166 |
+
"columns",
|
| 167 |
+
Index([("a",)], tupleize_cols=False),
|
| 168 |
+
),
|
| 169 |
+
(
|
| 170 |
+
[OrderedDict([(("a",), 1), (("b",), 2)])],
|
| 171 |
+
"columns",
|
| 172 |
+
Index([("a",), ("b",)], tupleize_cols=False),
|
| 173 |
+
),
|
| 174 |
+
([{("a", "b"): 1}], "columns", Index([("a", "b")], tupleize_cols=False)),
|
| 175 |
+
],
|
| 176 |
+
)
|
| 177 |
+
def test_constructor_from_dict_tuples(self, data_dict, orient, expected):
|
| 178 |
+
# GH#16769
|
| 179 |
+
df = DataFrame.from_dict(data_dict, orient)
|
| 180 |
+
result = df.columns
|
| 181 |
+
tm.assert_index_equal(result, expected)
|
| 182 |
+
|
| 183 |
+
def test_frame_dict_constructor_empty_series(self):
|
| 184 |
+
s1 = Series(
|
| 185 |
+
[1, 2, 3, 4], index=MultiIndex.from_tuples([(1, 2), (1, 3), (2, 2), (2, 4)])
|
| 186 |
+
)
|
| 187 |
+
s2 = Series(
|
| 188 |
+
[1, 2, 3, 4], index=MultiIndex.from_tuples([(1, 2), (1, 3), (3, 2), (3, 4)])
|
| 189 |
+
)
|
| 190 |
+
s3 = Series(dtype=object)
|
| 191 |
+
|
| 192 |
+
# it works!
|
| 193 |
+
DataFrame({"foo": s1, "bar": s2, "baz": s3})
|
| 194 |
+
DataFrame.from_dict({"foo": s1, "baz": s3, "bar": s2})
|
| 195 |
+
|
| 196 |
+
def test_from_dict_scalars_requires_index(self):
|
| 197 |
+
msg = "If using all scalar values, you must pass an index"
|
| 198 |
+
with pytest.raises(ValueError, match=msg):
|
| 199 |
+
DataFrame.from_dict(OrderedDict([("b", 8), ("a", 5), ("a", 6)]))
|
| 200 |
+
|
| 201 |
+
def test_from_dict_orient_invalid(self):
|
| 202 |
+
msg = (
|
| 203 |
+
"Expected 'index', 'columns' or 'tight' for orient parameter. "
|
| 204 |
+
"Got 'abc' instead"
|
| 205 |
+
)
|
| 206 |
+
with pytest.raises(ValueError, match=msg):
|
| 207 |
+
DataFrame.from_dict({"foo": 1, "baz": 3, "bar": 2}, orient="abc")
|
| 208 |
+
|
| 209 |
+
def test_from_dict_order_with_single_column(self):
|
| 210 |
+
data = {
|
| 211 |
+
"alpha": {
|
| 212 |
+
"value2": 123,
|
| 213 |
+
"value1": 532,
|
| 214 |
+
"animal": 222,
|
| 215 |
+
"plant": False,
|
| 216 |
+
"name": "test",
|
| 217 |
+
}
|
| 218 |
+
}
|
| 219 |
+
result = DataFrame.from_dict(
|
| 220 |
+
data,
|
| 221 |
+
orient="columns",
|
| 222 |
+
)
|
| 223 |
+
expected = DataFrame(
|
| 224 |
+
[[123], [532], [222], [False], ["test"]],
|
| 225 |
+
index=["value2", "value1", "animal", "plant", "name"],
|
| 226 |
+
columns=["alpha"],
|
| 227 |
+
)
|
| 228 |
+
tm.assert_frame_equal(result, expected)
|
lib/python3.12/site-packages/pandas/tests/frame/constructors/test_from_records.py
ADDED
|
@@ -0,0 +1,505 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from collections.abc import Iterator
|
| 2 |
+
from datetime import datetime
|
| 3 |
+
from decimal import Decimal
|
| 4 |
+
|
| 5 |
+
import numpy as np
|
| 6 |
+
import pytest
|
| 7 |
+
import pytz
|
| 8 |
+
|
| 9 |
+
from pandas._config import using_pyarrow_string_dtype
|
| 10 |
+
|
| 11 |
+
from pandas.compat import is_platform_little_endian
|
| 12 |
+
|
| 13 |
+
from pandas import (
|
| 14 |
+
CategoricalIndex,
|
| 15 |
+
DataFrame,
|
| 16 |
+
Index,
|
| 17 |
+
Interval,
|
| 18 |
+
RangeIndex,
|
| 19 |
+
Series,
|
| 20 |
+
date_range,
|
| 21 |
+
)
|
| 22 |
+
import pandas._testing as tm
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class TestFromRecords:
|
| 26 |
+
def test_from_records_dt64tz_frame(self):
|
| 27 |
+
# GH#51162 don't lose tz when calling from_records with DataFrame input
|
| 28 |
+
dti = date_range("2016-01-01", periods=10, tz="US/Pacific")
|
| 29 |
+
df = DataFrame({i: dti for i in range(4)})
|
| 30 |
+
with tm.assert_produces_warning(FutureWarning):
|
| 31 |
+
res = DataFrame.from_records(df)
|
| 32 |
+
tm.assert_frame_equal(res, df)
|
| 33 |
+
|
| 34 |
+
def test_from_records_with_datetimes(self):
|
| 35 |
+
# this may fail on certain platforms because of a numpy issue
|
| 36 |
+
# related GH#6140
|
| 37 |
+
if not is_platform_little_endian():
|
| 38 |
+
pytest.skip("known failure of test on non-little endian")
|
| 39 |
+
|
| 40 |
+
# construction with a null in a recarray
|
| 41 |
+
# GH#6140
|
| 42 |
+
expected = DataFrame({"EXPIRY": [datetime(2005, 3, 1, 0, 0), None]})
|
| 43 |
+
|
| 44 |
+
arrdata = [np.array([datetime(2005, 3, 1, 0, 0), None])]
|
| 45 |
+
dtypes = [("EXPIRY", "<M8[ns]")]
|
| 46 |
+
|
| 47 |
+
recarray = np.rec.fromarrays(arrdata, dtype=dtypes)
|
| 48 |
+
|
| 49 |
+
result = DataFrame.from_records(recarray)
|
| 50 |
+
tm.assert_frame_equal(result, expected)
|
| 51 |
+
|
| 52 |
+
# coercion should work too
|
| 53 |
+
arrdata = [np.array([datetime(2005, 3, 1, 0, 0), None])]
|
| 54 |
+
dtypes = [("EXPIRY", "<M8[m]")]
|
| 55 |
+
recarray = np.rec.fromarrays(arrdata, dtype=dtypes)
|
| 56 |
+
result = DataFrame.from_records(recarray)
|
| 57 |
+
# we get the closest supported unit, "s"
|
| 58 |
+
expected["EXPIRY"] = expected["EXPIRY"].astype("M8[s]")
|
| 59 |
+
tm.assert_frame_equal(result, expected)
|
| 60 |
+
|
| 61 |
+
@pytest.mark.skipif(
|
| 62 |
+
using_pyarrow_string_dtype(), reason="dtype checking logic doesn't work"
|
| 63 |
+
)
|
| 64 |
+
def test_from_records_sequencelike(self):
|
| 65 |
+
df = DataFrame(
|
| 66 |
+
{
|
| 67 |
+
"A": np.array(
|
| 68 |
+
np.random.default_rng(2).standard_normal(6), dtype=np.float64
|
| 69 |
+
),
|
| 70 |
+
"A1": np.array(
|
| 71 |
+
np.random.default_rng(2).standard_normal(6), dtype=np.float64
|
| 72 |
+
),
|
| 73 |
+
"B": np.array(np.arange(6), dtype=np.int64),
|
| 74 |
+
"C": ["foo"] * 6,
|
| 75 |
+
"D": np.array([True, False] * 3, dtype=bool),
|
| 76 |
+
"E": np.array(
|
| 77 |
+
np.random.default_rng(2).standard_normal(6), dtype=np.float32
|
| 78 |
+
),
|
| 79 |
+
"E1": np.array(
|
| 80 |
+
np.random.default_rng(2).standard_normal(6), dtype=np.float32
|
| 81 |
+
),
|
| 82 |
+
"F": np.array(np.arange(6), dtype=np.int32),
|
| 83 |
+
}
|
| 84 |
+
)
|
| 85 |
+
|
| 86 |
+
# this is actually tricky to create the recordlike arrays and
|
| 87 |
+
# have the dtypes be intact
|
| 88 |
+
blocks = df._to_dict_of_blocks()
|
| 89 |
+
tuples = []
|
| 90 |
+
columns = []
|
| 91 |
+
dtypes = []
|
| 92 |
+
for dtype, b in blocks.items():
|
| 93 |
+
columns.extend(b.columns)
|
| 94 |
+
dtypes.extend([(c, np.dtype(dtype).descr[0][1]) for c in b.columns])
|
| 95 |
+
for i in range(len(df.index)):
|
| 96 |
+
tup = []
|
| 97 |
+
for _, b in blocks.items():
|
| 98 |
+
tup.extend(b.iloc[i].values)
|
| 99 |
+
tuples.append(tuple(tup))
|
| 100 |
+
|
| 101 |
+
recarray = np.array(tuples, dtype=dtypes).view(np.rec.recarray)
|
| 102 |
+
recarray2 = df.to_records()
|
| 103 |
+
lists = [list(x) for x in tuples]
|
| 104 |
+
|
| 105 |
+
# tuples (lose the dtype info)
|
| 106 |
+
result = DataFrame.from_records(tuples, columns=columns).reindex(
|
| 107 |
+
columns=df.columns
|
| 108 |
+
)
|
| 109 |
+
|
| 110 |
+
# created recarray and with to_records recarray (have dtype info)
|
| 111 |
+
result2 = DataFrame.from_records(recarray, columns=columns).reindex(
|
| 112 |
+
columns=df.columns
|
| 113 |
+
)
|
| 114 |
+
result3 = DataFrame.from_records(recarray2, columns=columns).reindex(
|
| 115 |
+
columns=df.columns
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
# list of tuples (no dtype info)
|
| 119 |
+
result4 = DataFrame.from_records(lists, columns=columns).reindex(
|
| 120 |
+
columns=df.columns
|
| 121 |
+
)
|
| 122 |
+
|
| 123 |
+
tm.assert_frame_equal(result, df, check_dtype=False)
|
| 124 |
+
tm.assert_frame_equal(result2, df)
|
| 125 |
+
tm.assert_frame_equal(result3, df)
|
| 126 |
+
tm.assert_frame_equal(result4, df, check_dtype=False)
|
| 127 |
+
|
| 128 |
+
# tuples is in the order of the columns
|
| 129 |
+
result = DataFrame.from_records(tuples)
|
| 130 |
+
tm.assert_index_equal(result.columns, RangeIndex(8))
|
| 131 |
+
|
| 132 |
+
# test exclude parameter & we are casting the results here (as we don't
|
| 133 |
+
# have dtype info to recover)
|
| 134 |
+
columns_to_test = [columns.index("C"), columns.index("E1")]
|
| 135 |
+
|
| 136 |
+
exclude = list(set(range(8)) - set(columns_to_test))
|
| 137 |
+
result = DataFrame.from_records(tuples, exclude=exclude)
|
| 138 |
+
result.columns = [columns[i] for i in sorted(columns_to_test)]
|
| 139 |
+
tm.assert_series_equal(result["C"], df["C"])
|
| 140 |
+
tm.assert_series_equal(result["E1"], df["E1"])
|
| 141 |
+
|
| 142 |
+
def test_from_records_sequencelike_empty(self):
|
| 143 |
+
# empty case
|
| 144 |
+
result = DataFrame.from_records([], columns=["foo", "bar", "baz"])
|
| 145 |
+
assert len(result) == 0
|
| 146 |
+
tm.assert_index_equal(result.columns, Index(["foo", "bar", "baz"]))
|
| 147 |
+
|
| 148 |
+
result = DataFrame.from_records([])
|
| 149 |
+
assert len(result) == 0
|
| 150 |
+
assert len(result.columns) == 0
|
| 151 |
+
|
| 152 |
+
def test_from_records_dictlike(self):
|
| 153 |
+
# test the dict methods
|
| 154 |
+
df = DataFrame(
|
| 155 |
+
{
|
| 156 |
+
"A": np.array(
|
| 157 |
+
np.random.default_rng(2).standard_normal(6), dtype=np.float64
|
| 158 |
+
),
|
| 159 |
+
"A1": np.array(
|
| 160 |
+
np.random.default_rng(2).standard_normal(6), dtype=np.float64
|
| 161 |
+
),
|
| 162 |
+
"B": np.array(np.arange(6), dtype=np.int64),
|
| 163 |
+
"C": ["foo"] * 6,
|
| 164 |
+
"D": np.array([True, False] * 3, dtype=bool),
|
| 165 |
+
"E": np.array(
|
| 166 |
+
np.random.default_rng(2).standard_normal(6), dtype=np.float32
|
| 167 |
+
),
|
| 168 |
+
"E1": np.array(
|
| 169 |
+
np.random.default_rng(2).standard_normal(6), dtype=np.float32
|
| 170 |
+
),
|
| 171 |
+
"F": np.array(np.arange(6), dtype=np.int32),
|
| 172 |
+
}
|
| 173 |
+
)
|
| 174 |
+
|
| 175 |
+
# columns is in a different order here than the actual items iterated
|
| 176 |
+
# from the dict
|
| 177 |
+
blocks = df._to_dict_of_blocks()
|
| 178 |
+
columns = []
|
| 179 |
+
for b in blocks.values():
|
| 180 |
+
columns.extend(b.columns)
|
| 181 |
+
|
| 182 |
+
asdict = dict(df.items())
|
| 183 |
+
asdict2 = {x: y.values for x, y in df.items()}
|
| 184 |
+
|
| 185 |
+
# dict of series & dict of ndarrays (have dtype info)
|
| 186 |
+
results = []
|
| 187 |
+
results.append(DataFrame.from_records(asdict).reindex(columns=df.columns))
|
| 188 |
+
results.append(
|
| 189 |
+
DataFrame.from_records(asdict, columns=columns).reindex(columns=df.columns)
|
| 190 |
+
)
|
| 191 |
+
results.append(
|
| 192 |
+
DataFrame.from_records(asdict2, columns=columns).reindex(columns=df.columns)
|
| 193 |
+
)
|
| 194 |
+
|
| 195 |
+
for r in results:
|
| 196 |
+
tm.assert_frame_equal(r, df)
|
| 197 |
+
|
| 198 |
+
def test_from_records_with_index_data(self):
|
| 199 |
+
df = DataFrame(
|
| 200 |
+
np.random.default_rng(2).standard_normal((10, 3)), columns=["A", "B", "C"]
|
| 201 |
+
)
|
| 202 |
+
|
| 203 |
+
data = np.random.default_rng(2).standard_normal(10)
|
| 204 |
+
with tm.assert_produces_warning(FutureWarning):
|
| 205 |
+
df1 = DataFrame.from_records(df, index=data)
|
| 206 |
+
tm.assert_index_equal(df1.index, Index(data))
|
| 207 |
+
|
| 208 |
+
def test_from_records_bad_index_column(self):
|
| 209 |
+
df = DataFrame(
|
| 210 |
+
np.random.default_rng(2).standard_normal((10, 3)), columns=["A", "B", "C"]
|
| 211 |
+
)
|
| 212 |
+
|
| 213 |
+
# should pass
|
| 214 |
+
with tm.assert_produces_warning(FutureWarning):
|
| 215 |
+
df1 = DataFrame.from_records(df, index=["C"])
|
| 216 |
+
tm.assert_index_equal(df1.index, Index(df.C))
|
| 217 |
+
|
| 218 |
+
with tm.assert_produces_warning(FutureWarning):
|
| 219 |
+
df1 = DataFrame.from_records(df, index="C")
|
| 220 |
+
tm.assert_index_equal(df1.index, Index(df.C))
|
| 221 |
+
|
| 222 |
+
# should fail
|
| 223 |
+
msg = "|".join(
|
| 224 |
+
[
|
| 225 |
+
r"'None of \[2\] are in the columns'",
|
| 226 |
+
]
|
| 227 |
+
)
|
| 228 |
+
with pytest.raises(KeyError, match=msg):
|
| 229 |
+
with tm.assert_produces_warning(FutureWarning):
|
| 230 |
+
DataFrame.from_records(df, index=[2])
|
| 231 |
+
with pytest.raises(KeyError, match=msg):
|
| 232 |
+
with tm.assert_produces_warning(FutureWarning):
|
| 233 |
+
DataFrame.from_records(df, index=2)
|
| 234 |
+
|
| 235 |
+
def test_from_records_non_tuple(self):
|
| 236 |
+
class Record:
|
| 237 |
+
def __init__(self, *args) -> None:
|
| 238 |
+
self.args = args
|
| 239 |
+
|
| 240 |
+
def __getitem__(self, i):
|
| 241 |
+
return self.args[i]
|
| 242 |
+
|
| 243 |
+
def __iter__(self) -> Iterator:
|
| 244 |
+
return iter(self.args)
|
| 245 |
+
|
| 246 |
+
recs = [Record(1, 2, 3), Record(4, 5, 6), Record(7, 8, 9)]
|
| 247 |
+
tups = [tuple(rec) for rec in recs]
|
| 248 |
+
|
| 249 |
+
result = DataFrame.from_records(recs)
|
| 250 |
+
expected = DataFrame.from_records(tups)
|
| 251 |
+
tm.assert_frame_equal(result, expected)
|
| 252 |
+
|
| 253 |
+
def test_from_records_len0_with_columns(self):
|
| 254 |
+
# GH#2633
|
| 255 |
+
result = DataFrame.from_records([], index="foo", columns=["foo", "bar"])
|
| 256 |
+
expected = Index(["bar"])
|
| 257 |
+
|
| 258 |
+
assert len(result) == 0
|
| 259 |
+
assert result.index.name == "foo"
|
| 260 |
+
tm.assert_index_equal(result.columns, expected)
|
| 261 |
+
|
| 262 |
+
def test_from_records_series_list_dict(self):
|
| 263 |
+
# GH#27358
|
| 264 |
+
expected = DataFrame([[{"a": 1, "b": 2}, {"a": 3, "b": 4}]]).T
|
| 265 |
+
data = Series([[{"a": 1, "b": 2}], [{"a": 3, "b": 4}]])
|
| 266 |
+
result = DataFrame.from_records(data)
|
| 267 |
+
tm.assert_frame_equal(result, expected)
|
| 268 |
+
|
| 269 |
+
def test_from_records_series_categorical_index(self):
|
| 270 |
+
# GH#32805
|
| 271 |
+
index = CategoricalIndex(
|
| 272 |
+
[Interval(-20, -10), Interval(-10, 0), Interval(0, 10)]
|
| 273 |
+
)
|
| 274 |
+
series_of_dicts = Series([{"a": 1}, {"a": 2}, {"b": 3}], index=index)
|
| 275 |
+
frame = DataFrame.from_records(series_of_dicts, index=index)
|
| 276 |
+
expected = DataFrame(
|
| 277 |
+
{"a": [1, 2, np.nan], "b": [np.nan, np.nan, 3]}, index=index
|
| 278 |
+
)
|
| 279 |
+
tm.assert_frame_equal(frame, expected)
|
| 280 |
+
|
| 281 |
+
def test_frame_from_records_utc(self):
|
| 282 |
+
rec = {"datum": 1.5, "begin_time": datetime(2006, 4, 27, tzinfo=pytz.utc)}
|
| 283 |
+
|
| 284 |
+
# it works
|
| 285 |
+
DataFrame.from_records([rec], index="begin_time")
|
| 286 |
+
|
| 287 |
+
def test_from_records_to_records(self):
|
| 288 |
+
# from numpy documentation
|
| 289 |
+
arr = np.zeros((2,), dtype=("i4,f4,S10"))
|
| 290 |
+
arr[:] = [(1, 2.0, "Hello"), (2, 3.0, "World")]
|
| 291 |
+
|
| 292 |
+
DataFrame.from_records(arr)
|
| 293 |
+
|
| 294 |
+
index = Index(np.arange(len(arr))[::-1])
|
| 295 |
+
indexed_frame = DataFrame.from_records(arr, index=index)
|
| 296 |
+
tm.assert_index_equal(indexed_frame.index, index)
|
| 297 |
+
|
| 298 |
+
# without names, it should go to last ditch
|
| 299 |
+
arr2 = np.zeros((2, 3))
|
| 300 |
+
tm.assert_frame_equal(DataFrame.from_records(arr2), DataFrame(arr2))
|
| 301 |
+
|
| 302 |
+
# wrong length
|
| 303 |
+
msg = "|".join(
|
| 304 |
+
[
|
| 305 |
+
r"Length of values \(2\) does not match length of index \(1\)",
|
| 306 |
+
]
|
| 307 |
+
)
|
| 308 |
+
with pytest.raises(ValueError, match=msg):
|
| 309 |
+
DataFrame.from_records(arr, index=index[:-1])
|
| 310 |
+
|
| 311 |
+
indexed_frame = DataFrame.from_records(arr, index="f1")
|
| 312 |
+
|
| 313 |
+
# what to do?
|
| 314 |
+
records = indexed_frame.to_records()
|
| 315 |
+
assert len(records.dtype.names) == 3
|
| 316 |
+
|
| 317 |
+
records = indexed_frame.to_records(index=False)
|
| 318 |
+
assert len(records.dtype.names) == 2
|
| 319 |
+
assert "index" not in records.dtype.names
|
| 320 |
+
|
| 321 |
+
def test_from_records_nones(self):
|
| 322 |
+
tuples = [(1, 2, None, 3), (1, 2, None, 3), (None, 2, 5, 3)]
|
| 323 |
+
|
| 324 |
+
df = DataFrame.from_records(tuples, columns=["a", "b", "c", "d"])
|
| 325 |
+
assert np.isnan(df["c"][0])
|
| 326 |
+
|
| 327 |
+
def test_from_records_iterator(self):
|
| 328 |
+
arr = np.array(
|
| 329 |
+
[(1.0, 1.0, 2, 2), (3.0, 3.0, 4, 4), (5.0, 5.0, 6, 6), (7.0, 7.0, 8, 8)],
|
| 330 |
+
dtype=[
|
| 331 |
+
("x", np.float64),
|
| 332 |
+
("u", np.float32),
|
| 333 |
+
("y", np.int64),
|
| 334 |
+
("z", np.int32),
|
| 335 |
+
],
|
| 336 |
+
)
|
| 337 |
+
df = DataFrame.from_records(iter(arr), nrows=2)
|
| 338 |
+
xp = DataFrame(
|
| 339 |
+
{
|
| 340 |
+
"x": np.array([1.0, 3.0], dtype=np.float64),
|
| 341 |
+
"u": np.array([1.0, 3.0], dtype=np.float32),
|
| 342 |
+
"y": np.array([2, 4], dtype=np.int64),
|
| 343 |
+
"z": np.array([2, 4], dtype=np.int32),
|
| 344 |
+
}
|
| 345 |
+
)
|
| 346 |
+
tm.assert_frame_equal(df.reindex_like(xp), xp)
|
| 347 |
+
|
| 348 |
+
# no dtypes specified here, so just compare with the default
|
| 349 |
+
arr = [(1.0, 2), (3.0, 4), (5.0, 6), (7.0, 8)]
|
| 350 |
+
df = DataFrame.from_records(iter(arr), columns=["x", "y"], nrows=2)
|
| 351 |
+
tm.assert_frame_equal(df, xp.reindex(columns=["x", "y"]), check_dtype=False)
|
| 352 |
+
|
| 353 |
+
def test_from_records_tuples_generator(self):
|
| 354 |
+
def tuple_generator(length):
|
| 355 |
+
for i in range(length):
|
| 356 |
+
letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
| 357 |
+
yield (i, letters[i % len(letters)], i / length)
|
| 358 |
+
|
| 359 |
+
columns_names = ["Integer", "String", "Float"]
|
| 360 |
+
columns = [
|
| 361 |
+
[i[j] for i in tuple_generator(10)] for j in range(len(columns_names))
|
| 362 |
+
]
|
| 363 |
+
data = {"Integer": columns[0], "String": columns[1], "Float": columns[2]}
|
| 364 |
+
expected = DataFrame(data, columns=columns_names)
|
| 365 |
+
|
| 366 |
+
generator = tuple_generator(10)
|
| 367 |
+
result = DataFrame.from_records(generator, columns=columns_names)
|
| 368 |
+
tm.assert_frame_equal(result, expected)
|
| 369 |
+
|
| 370 |
+
def test_from_records_lists_generator(self):
|
| 371 |
+
def list_generator(length):
|
| 372 |
+
for i in range(length):
|
| 373 |
+
letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
| 374 |
+
yield [i, letters[i % len(letters)], i / length]
|
| 375 |
+
|
| 376 |
+
columns_names = ["Integer", "String", "Float"]
|
| 377 |
+
columns = [
|
| 378 |
+
[i[j] for i in list_generator(10)] for j in range(len(columns_names))
|
| 379 |
+
]
|
| 380 |
+
data = {"Integer": columns[0], "String": columns[1], "Float": columns[2]}
|
| 381 |
+
expected = DataFrame(data, columns=columns_names)
|
| 382 |
+
|
| 383 |
+
generator = list_generator(10)
|
| 384 |
+
result = DataFrame.from_records(generator, columns=columns_names)
|
| 385 |
+
tm.assert_frame_equal(result, expected)
|
| 386 |
+
|
| 387 |
+
def test_from_records_columns_not_modified(self):
|
| 388 |
+
tuples = [(1, 2, 3), (1, 2, 3), (2, 5, 3)]
|
| 389 |
+
|
| 390 |
+
columns = ["a", "b", "c"]
|
| 391 |
+
original_columns = list(columns)
|
| 392 |
+
|
| 393 |
+
DataFrame.from_records(tuples, columns=columns, index="a")
|
| 394 |
+
|
| 395 |
+
assert columns == original_columns
|
| 396 |
+
|
| 397 |
+
def test_from_records_decimal(self):
|
| 398 |
+
tuples = [(Decimal("1.5"),), (Decimal("2.5"),), (None,)]
|
| 399 |
+
|
| 400 |
+
df = DataFrame.from_records(tuples, columns=["a"])
|
| 401 |
+
assert df["a"].dtype == object
|
| 402 |
+
|
| 403 |
+
df = DataFrame.from_records(tuples, columns=["a"], coerce_float=True)
|
| 404 |
+
assert df["a"].dtype == np.float64
|
| 405 |
+
assert np.isnan(df["a"].values[-1])
|
| 406 |
+
|
| 407 |
+
def test_from_records_duplicates(self):
|
| 408 |
+
result = DataFrame.from_records([(1, 2, 3), (4, 5, 6)], columns=["a", "b", "a"])
|
| 409 |
+
|
| 410 |
+
expected = DataFrame([(1, 2, 3), (4, 5, 6)], columns=["a", "b", "a"])
|
| 411 |
+
|
| 412 |
+
tm.assert_frame_equal(result, expected)
|
| 413 |
+
|
| 414 |
+
def test_from_records_set_index_name(self):
|
| 415 |
+
def create_dict(order_id):
|
| 416 |
+
return {
|
| 417 |
+
"order_id": order_id,
|
| 418 |
+
"quantity": np.random.default_rng(2).integers(1, 10),
|
| 419 |
+
"price": np.random.default_rng(2).integers(1, 10),
|
| 420 |
+
}
|
| 421 |
+
|
| 422 |
+
documents = [create_dict(i) for i in range(10)]
|
| 423 |
+
# demo missing data
|
| 424 |
+
documents.append({"order_id": 10, "quantity": 5})
|
| 425 |
+
|
| 426 |
+
result = DataFrame.from_records(documents, index="order_id")
|
| 427 |
+
assert result.index.name == "order_id"
|
| 428 |
+
|
| 429 |
+
# MultiIndex
|
| 430 |
+
result = DataFrame.from_records(documents, index=["order_id", "quantity"])
|
| 431 |
+
assert result.index.names == ("order_id", "quantity")
|
| 432 |
+
|
| 433 |
+
def test_from_records_misc_brokenness(self):
|
| 434 |
+
# GH#2179
|
| 435 |
+
|
| 436 |
+
data = {1: ["foo"], 2: ["bar"]}
|
| 437 |
+
|
| 438 |
+
result = DataFrame.from_records(data, columns=["a", "b"])
|
| 439 |
+
exp = DataFrame(data, columns=["a", "b"])
|
| 440 |
+
tm.assert_frame_equal(result, exp)
|
| 441 |
+
|
| 442 |
+
# overlap in index/index_names
|
| 443 |
+
|
| 444 |
+
data = {"a": [1, 2, 3], "b": [4, 5, 6]}
|
| 445 |
+
|
| 446 |
+
result = DataFrame.from_records(data, index=["a", "b", "c"])
|
| 447 |
+
exp = DataFrame(data, index=["a", "b", "c"])
|
| 448 |
+
tm.assert_frame_equal(result, exp)
|
| 449 |
+
|
| 450 |
+
def test_from_records_misc_brokenness2(self):
|
| 451 |
+
# GH#2623
|
| 452 |
+
rows = []
|
| 453 |
+
rows.append([datetime(2010, 1, 1), 1])
|
| 454 |
+
rows.append([datetime(2010, 1, 2), "hi"]) # test col upconverts to obj
|
| 455 |
+
result = DataFrame.from_records(rows, columns=["date", "test"])
|
| 456 |
+
expected = DataFrame(
|
| 457 |
+
{"date": [row[0] for row in rows], "test": [row[1] for row in rows]}
|
| 458 |
+
)
|
| 459 |
+
tm.assert_frame_equal(result, expected)
|
| 460 |
+
assert result.dtypes["test"] == np.dtype(object)
|
| 461 |
+
|
| 462 |
+
def test_from_records_misc_brokenness3(self):
|
| 463 |
+
rows = []
|
| 464 |
+
rows.append([datetime(2010, 1, 1), 1])
|
| 465 |
+
rows.append([datetime(2010, 1, 2), 1])
|
| 466 |
+
result = DataFrame.from_records(rows, columns=["date", "test"])
|
| 467 |
+
expected = DataFrame(
|
| 468 |
+
{"date": [row[0] for row in rows], "test": [row[1] for row in rows]}
|
| 469 |
+
)
|
| 470 |
+
tm.assert_frame_equal(result, expected)
|
| 471 |
+
|
| 472 |
+
def test_from_records_empty(self):
|
| 473 |
+
# GH#3562
|
| 474 |
+
result = DataFrame.from_records([], columns=["a", "b", "c"])
|
| 475 |
+
expected = DataFrame(columns=["a", "b", "c"])
|
| 476 |
+
tm.assert_frame_equal(result, expected)
|
| 477 |
+
|
| 478 |
+
result = DataFrame.from_records([], columns=["a", "b", "b"])
|
| 479 |
+
expected = DataFrame(columns=["a", "b", "b"])
|
| 480 |
+
tm.assert_frame_equal(result, expected)
|
| 481 |
+
|
| 482 |
+
def test_from_records_empty_with_nonempty_fields_gh3682(self):
|
| 483 |
+
a = np.array([(1, 2)], dtype=[("id", np.int64), ("value", np.int64)])
|
| 484 |
+
df = DataFrame.from_records(a, index="id")
|
| 485 |
+
|
| 486 |
+
ex_index = Index([1], name="id")
|
| 487 |
+
expected = DataFrame({"value": [2]}, index=ex_index, columns=["value"])
|
| 488 |
+
tm.assert_frame_equal(df, expected)
|
| 489 |
+
|
| 490 |
+
b = a[:0]
|
| 491 |
+
df2 = DataFrame.from_records(b, index="id")
|
| 492 |
+
tm.assert_frame_equal(df2, df.iloc[:0])
|
| 493 |
+
|
| 494 |
+
def test_from_records_empty2(self):
|
| 495 |
+
# GH#42456
|
| 496 |
+
dtype = [("prop", int)]
|
| 497 |
+
shape = (0, len(dtype))
|
| 498 |
+
arr = np.empty(shape, dtype=dtype)
|
| 499 |
+
|
| 500 |
+
result = DataFrame.from_records(arr)
|
| 501 |
+
expected = DataFrame({"prop": np.array([], dtype=int)})
|
| 502 |
+
tm.assert_frame_equal(result, expected)
|
| 503 |
+
|
| 504 |
+
alt = DataFrame(arr)
|
| 505 |
+
tm.assert_frame_equal(alt, expected)
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/__init__.py
ADDED
|
File without changes
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (206 Bytes). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_coercion.cpython-312.pyc
ADDED
|
Binary file (9.98 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_delitem.cpython-312.pyc
ADDED
|
Binary file (3.49 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_get.cpython-312.pyc
ADDED
|
Binary file (1.45 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_get_value.cpython-312.pyc
ADDED
|
Binary file (1.53 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_getitem.cpython-312.pyc
ADDED
|
Binary file (24.4 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_insert.cpython-312.pyc
ADDED
|
Binary file (7.15 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_mask.cpython-312.pyc
ADDED
|
Binary file (9.86 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_set_value.cpython-312.pyc
ADDED
|
Binary file (4.49 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_setitem.cpython-312.pyc
ADDED
|
Binary file (81.8 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_take.cpython-312.pyc
ADDED
|
Binary file (5.38 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_where.cpython-312.pyc
ADDED
|
Binary file (61 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/__pycache__/test_xs.cpython-312.pyc
ADDED
|
Binary file (22.9 kB). View file
|
|
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/test_coercion.py
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Tests for values coercion in setitem-like operations on DataFrame.
|
| 3 |
+
|
| 4 |
+
For the most part, these should be multi-column DataFrames, otherwise
|
| 5 |
+
we would share the tests with Series.
|
| 6 |
+
"""
|
| 7 |
+
import numpy as np
|
| 8 |
+
import pytest
|
| 9 |
+
|
| 10 |
+
import pandas as pd
|
| 11 |
+
from pandas import (
|
| 12 |
+
DataFrame,
|
| 13 |
+
MultiIndex,
|
| 14 |
+
NaT,
|
| 15 |
+
Series,
|
| 16 |
+
Timestamp,
|
| 17 |
+
date_range,
|
| 18 |
+
)
|
| 19 |
+
import pandas._testing as tm
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class TestDataFrameSetitemCoercion:
|
| 23 |
+
@pytest.mark.parametrize("consolidate", [True, False])
|
| 24 |
+
def test_loc_setitem_multiindex_columns(self, consolidate):
|
| 25 |
+
# GH#18415 Setting values in a single column preserves dtype,
|
| 26 |
+
# while setting them in multiple columns did unwanted cast.
|
| 27 |
+
|
| 28 |
+
# Note that A here has 2 blocks, below we do the same thing
|
| 29 |
+
# with a consolidated frame.
|
| 30 |
+
A = DataFrame(np.zeros((6, 5), dtype=np.float32))
|
| 31 |
+
A = pd.concat([A, A], axis=1, keys=[1, 2])
|
| 32 |
+
if consolidate:
|
| 33 |
+
A = A._consolidate()
|
| 34 |
+
|
| 35 |
+
A.loc[2:3, (1, slice(2, 3))] = np.ones((2, 2), dtype=np.float32)
|
| 36 |
+
assert (A.dtypes == np.float32).all()
|
| 37 |
+
|
| 38 |
+
A.loc[0:5, (1, slice(2, 3))] = np.ones((6, 2), dtype=np.float32)
|
| 39 |
+
|
| 40 |
+
assert (A.dtypes == np.float32).all()
|
| 41 |
+
|
| 42 |
+
A.loc[:, (1, slice(2, 3))] = np.ones((6, 2), dtype=np.float32)
|
| 43 |
+
assert (A.dtypes == np.float32).all()
|
| 44 |
+
|
| 45 |
+
# TODO: i think this isn't about MultiIndex and could be done with iloc?
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def test_37477():
|
| 49 |
+
# fixed by GH#45121
|
| 50 |
+
orig = DataFrame({"A": [1, 2, 3], "B": [3, 4, 5]})
|
| 51 |
+
expected = DataFrame({"A": [1, 2, 3], "B": [3, 1.2, 5]})
|
| 52 |
+
|
| 53 |
+
df = orig.copy()
|
| 54 |
+
with tm.assert_produces_warning(
|
| 55 |
+
FutureWarning, match="Setting an item of incompatible dtype"
|
| 56 |
+
):
|
| 57 |
+
df.at[1, "B"] = 1.2
|
| 58 |
+
tm.assert_frame_equal(df, expected)
|
| 59 |
+
|
| 60 |
+
df = orig.copy()
|
| 61 |
+
with tm.assert_produces_warning(
|
| 62 |
+
FutureWarning, match="Setting an item of incompatible dtype"
|
| 63 |
+
):
|
| 64 |
+
df.loc[1, "B"] = 1.2
|
| 65 |
+
tm.assert_frame_equal(df, expected)
|
| 66 |
+
|
| 67 |
+
df = orig.copy()
|
| 68 |
+
with tm.assert_produces_warning(
|
| 69 |
+
FutureWarning, match="Setting an item of incompatible dtype"
|
| 70 |
+
):
|
| 71 |
+
df.iat[1, 1] = 1.2
|
| 72 |
+
tm.assert_frame_equal(df, expected)
|
| 73 |
+
|
| 74 |
+
df = orig.copy()
|
| 75 |
+
with tm.assert_produces_warning(
|
| 76 |
+
FutureWarning, match="Setting an item of incompatible dtype"
|
| 77 |
+
):
|
| 78 |
+
df.iloc[1, 1] = 1.2
|
| 79 |
+
tm.assert_frame_equal(df, expected)
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def test_6942(indexer_al):
|
| 83 |
+
# check that the .at __setitem__ after setting "Live" actually sets the data
|
| 84 |
+
start = Timestamp("2014-04-01")
|
| 85 |
+
t1 = Timestamp("2014-04-23 12:42:38.883082")
|
| 86 |
+
t2 = Timestamp("2014-04-24 01:33:30.040039")
|
| 87 |
+
|
| 88 |
+
dti = date_range(start, periods=1)
|
| 89 |
+
orig = DataFrame(index=dti, columns=["timenow", "Live"])
|
| 90 |
+
|
| 91 |
+
df = orig.copy()
|
| 92 |
+
indexer_al(df)[start, "timenow"] = t1
|
| 93 |
+
|
| 94 |
+
df["Live"] = True
|
| 95 |
+
|
| 96 |
+
df.at[start, "timenow"] = t2
|
| 97 |
+
assert df.iloc[0, 0] == t2
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
def test_26395(indexer_al):
|
| 101 |
+
# .at case fixed by GH#45121 (best guess)
|
| 102 |
+
df = DataFrame(index=["A", "B", "C"])
|
| 103 |
+
df["D"] = 0
|
| 104 |
+
|
| 105 |
+
indexer_al(df)["C", "D"] = 2
|
| 106 |
+
expected = DataFrame({"D": [0, 0, 2]}, index=["A", "B", "C"], dtype=np.int64)
|
| 107 |
+
tm.assert_frame_equal(df, expected)
|
| 108 |
+
|
| 109 |
+
with tm.assert_produces_warning(
|
| 110 |
+
FutureWarning, match="Setting an item of incompatible dtype"
|
| 111 |
+
):
|
| 112 |
+
indexer_al(df)["C", "D"] = 44.5
|
| 113 |
+
expected = DataFrame({"D": [0, 0, 44.5]}, index=["A", "B", "C"], dtype=np.float64)
|
| 114 |
+
tm.assert_frame_equal(df, expected)
|
| 115 |
+
|
| 116 |
+
with tm.assert_produces_warning(
|
| 117 |
+
FutureWarning, match="Setting an item of incompatible dtype"
|
| 118 |
+
):
|
| 119 |
+
indexer_al(df)["C", "D"] = "hello"
|
| 120 |
+
expected = DataFrame({"D": [0, 0, "hello"]}, index=["A", "B", "C"], dtype=object)
|
| 121 |
+
tm.assert_frame_equal(df, expected)
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
@pytest.mark.xfail(reason="unwanted upcast")
|
| 125 |
+
def test_15231():
|
| 126 |
+
df = DataFrame([[1, 2], [3, 4]], columns=["a", "b"])
|
| 127 |
+
df.loc[2] = Series({"a": 5, "b": 6})
|
| 128 |
+
assert (df.dtypes == np.int64).all()
|
| 129 |
+
|
| 130 |
+
df.loc[3] = Series({"a": 7})
|
| 131 |
+
|
| 132 |
+
# df["a"] doesn't have any NaNs, should not have been cast
|
| 133 |
+
exp_dtypes = Series([np.int64, np.float64], dtype=object, index=["a", "b"])
|
| 134 |
+
tm.assert_series_equal(df.dtypes, exp_dtypes)
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def test_iloc_setitem_unnecesssary_float_upcasting():
|
| 138 |
+
# GH#12255
|
| 139 |
+
df = DataFrame(
|
| 140 |
+
{
|
| 141 |
+
0: np.array([1, 3], dtype=np.float32),
|
| 142 |
+
1: np.array([2, 4], dtype=np.float32),
|
| 143 |
+
2: ["a", "b"],
|
| 144 |
+
}
|
| 145 |
+
)
|
| 146 |
+
orig = df.copy()
|
| 147 |
+
|
| 148 |
+
values = df[0].values.reshape(2, 1)
|
| 149 |
+
df.iloc[:, 0:1] = values
|
| 150 |
+
|
| 151 |
+
tm.assert_frame_equal(df, orig)
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
@pytest.mark.xfail(reason="unwanted casting to dt64")
|
| 155 |
+
def test_12499():
|
| 156 |
+
# TODO: OP in GH#12499 used np.datetim64("NaT") instead of pd.NaT,
|
| 157 |
+
# which has consequences for the expected df["two"] (though i think at
|
| 158 |
+
# the time it might not have because of a separate bug). See if it makes
|
| 159 |
+
# a difference which one we use here.
|
| 160 |
+
ts = Timestamp("2016-03-01 03:13:22.98986", tz="UTC")
|
| 161 |
+
|
| 162 |
+
data = [{"one": 0, "two": ts}]
|
| 163 |
+
orig = DataFrame(data)
|
| 164 |
+
df = orig.copy()
|
| 165 |
+
df.loc[1] = [np.nan, NaT]
|
| 166 |
+
|
| 167 |
+
expected = DataFrame(
|
| 168 |
+
{"one": [0, np.nan], "two": Series([ts, NaT], dtype="datetime64[ns, UTC]")}
|
| 169 |
+
)
|
| 170 |
+
tm.assert_frame_equal(df, expected)
|
| 171 |
+
|
| 172 |
+
data = [{"one": 0, "two": ts}]
|
| 173 |
+
df = orig.copy()
|
| 174 |
+
df.loc[1, :] = [np.nan, NaT]
|
| 175 |
+
tm.assert_frame_equal(df, expected)
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
def test_20476():
|
| 179 |
+
mi = MultiIndex.from_product([["A", "B"], ["a", "b", "c"]])
|
| 180 |
+
df = DataFrame(-1, index=range(3), columns=mi)
|
| 181 |
+
filler = DataFrame([[1, 2, 3.0]] * 3, index=range(3), columns=["a", "b", "c"])
|
| 182 |
+
df["A"] = filler
|
| 183 |
+
|
| 184 |
+
expected = DataFrame(
|
| 185 |
+
{
|
| 186 |
+
0: [1, 1, 1],
|
| 187 |
+
1: [2, 2, 2],
|
| 188 |
+
2: [3.0, 3.0, 3.0],
|
| 189 |
+
3: [-1, -1, -1],
|
| 190 |
+
4: [-1, -1, -1],
|
| 191 |
+
5: [-1, -1, -1],
|
| 192 |
+
}
|
| 193 |
+
)
|
| 194 |
+
expected.columns = mi
|
| 195 |
+
exp_dtypes = Series(
|
| 196 |
+
[np.dtype(np.int64)] * 2 + [np.dtype(np.float64)] + [np.dtype(np.int64)] * 3,
|
| 197 |
+
index=mi,
|
| 198 |
+
)
|
| 199 |
+
tm.assert_series_equal(df.dtypes, exp_dtypes)
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/test_delitem.py
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import re
|
| 2 |
+
|
| 3 |
+
import numpy as np
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from pandas import (
|
| 7 |
+
DataFrame,
|
| 8 |
+
MultiIndex,
|
| 9 |
+
)
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
class TestDataFrameDelItem:
|
| 13 |
+
def test_delitem(self, float_frame):
|
| 14 |
+
del float_frame["A"]
|
| 15 |
+
assert "A" not in float_frame
|
| 16 |
+
|
| 17 |
+
def test_delitem_multiindex(self):
|
| 18 |
+
midx = MultiIndex.from_product([["A", "B"], [1, 2]])
|
| 19 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((4, 4)), columns=midx)
|
| 20 |
+
assert len(df.columns) == 4
|
| 21 |
+
assert ("A",) in df.columns
|
| 22 |
+
assert "A" in df.columns
|
| 23 |
+
|
| 24 |
+
result = df["A"]
|
| 25 |
+
assert isinstance(result, DataFrame)
|
| 26 |
+
del df["A"]
|
| 27 |
+
|
| 28 |
+
assert len(df.columns) == 2
|
| 29 |
+
|
| 30 |
+
# A still in the levels, BUT get a KeyError if trying
|
| 31 |
+
# to delete
|
| 32 |
+
assert ("A",) not in df.columns
|
| 33 |
+
with pytest.raises(KeyError, match=re.escape("('A',)")):
|
| 34 |
+
del df[("A",)]
|
| 35 |
+
|
| 36 |
+
# behavior of dropped/deleted MultiIndex levels changed from
|
| 37 |
+
# GH 2770 to GH 19027: MultiIndex no longer '.__contains__'
|
| 38 |
+
# levels which are dropped/deleted
|
| 39 |
+
assert "A" not in df.columns
|
| 40 |
+
with pytest.raises(KeyError, match=re.escape("('A',)")):
|
| 41 |
+
del df["A"]
|
| 42 |
+
|
| 43 |
+
def test_delitem_corner(self, float_frame):
|
| 44 |
+
f = float_frame.copy()
|
| 45 |
+
del f["D"]
|
| 46 |
+
assert len(f.columns) == 3
|
| 47 |
+
with pytest.raises(KeyError, match=r"^'D'$"):
|
| 48 |
+
del f["D"]
|
| 49 |
+
del f["B"]
|
| 50 |
+
assert len(f.columns) == 2
|
| 51 |
+
|
| 52 |
+
def test_delitem_col_still_multiindex(self):
|
| 53 |
+
arrays = [["a", "b", "c", "top"], ["", "", "", "OD"], ["", "", "", "wx"]]
|
| 54 |
+
|
| 55 |
+
tuples = sorted(zip(*arrays))
|
| 56 |
+
index = MultiIndex.from_tuples(tuples)
|
| 57 |
+
|
| 58 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((3, 4)), columns=index)
|
| 59 |
+
del df[("a", "", "")]
|
| 60 |
+
assert isinstance(df.columns, MultiIndex)
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/test_get.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
|
| 3 |
+
from pandas import DataFrame
|
| 4 |
+
import pandas._testing as tm
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class TestGet:
|
| 8 |
+
def test_get(self, float_frame):
|
| 9 |
+
b = float_frame.get("B")
|
| 10 |
+
tm.assert_series_equal(b, float_frame["B"])
|
| 11 |
+
|
| 12 |
+
assert float_frame.get("foo") is None
|
| 13 |
+
tm.assert_series_equal(
|
| 14 |
+
float_frame.get("foo", float_frame["B"]), float_frame["B"]
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
@pytest.mark.parametrize(
|
| 18 |
+
"df",
|
| 19 |
+
[
|
| 20 |
+
DataFrame(),
|
| 21 |
+
DataFrame(columns=list("AB")),
|
| 22 |
+
DataFrame(columns=list("AB"), index=range(3)),
|
| 23 |
+
],
|
| 24 |
+
)
|
| 25 |
+
def test_get_none(self, df):
|
| 26 |
+
# see gh-5652
|
| 27 |
+
assert df.get(None) is None
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/test_get_value.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
|
| 3 |
+
from pandas import (
|
| 4 |
+
DataFrame,
|
| 5 |
+
MultiIndex,
|
| 6 |
+
)
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class TestGetValue:
|
| 10 |
+
def test_get_set_value_no_partial_indexing(self):
|
| 11 |
+
# partial w/ MultiIndex raise exception
|
| 12 |
+
index = MultiIndex.from_tuples([(0, 1), (0, 2), (1, 1), (1, 2)])
|
| 13 |
+
df = DataFrame(index=index, columns=range(4))
|
| 14 |
+
with pytest.raises(KeyError, match=r"^0$"):
|
| 15 |
+
df._get_value(0, 1)
|
| 16 |
+
|
| 17 |
+
def test_get_value(self, float_frame):
|
| 18 |
+
for idx in float_frame.index:
|
| 19 |
+
for col in float_frame.columns:
|
| 20 |
+
result = float_frame._get_value(idx, col)
|
| 21 |
+
expected = float_frame[col][idx]
|
| 22 |
+
assert result == expected
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/test_getitem.py
ADDED
|
@@ -0,0 +1,472 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import re
|
| 2 |
+
|
| 3 |
+
import numpy as np
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
from pandas import (
|
| 7 |
+
Categorical,
|
| 8 |
+
CategoricalDtype,
|
| 9 |
+
CategoricalIndex,
|
| 10 |
+
DataFrame,
|
| 11 |
+
DateOffset,
|
| 12 |
+
DatetimeIndex,
|
| 13 |
+
Index,
|
| 14 |
+
MultiIndex,
|
| 15 |
+
Series,
|
| 16 |
+
Timestamp,
|
| 17 |
+
concat,
|
| 18 |
+
date_range,
|
| 19 |
+
get_dummies,
|
| 20 |
+
period_range,
|
| 21 |
+
)
|
| 22 |
+
import pandas._testing as tm
|
| 23 |
+
from pandas.core.arrays import SparseArray
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
class TestGetitem:
|
| 27 |
+
def test_getitem_unused_level_raises(self):
|
| 28 |
+
# GH#20410
|
| 29 |
+
mi = MultiIndex(
|
| 30 |
+
levels=[["a_lot", "onlyone", "notevenone"], [1970, ""]],
|
| 31 |
+
codes=[[1, 0], [1, 0]],
|
| 32 |
+
)
|
| 33 |
+
df = DataFrame(-1, index=range(3), columns=mi)
|
| 34 |
+
|
| 35 |
+
with pytest.raises(KeyError, match="notevenone"):
|
| 36 |
+
df["notevenone"]
|
| 37 |
+
|
| 38 |
+
def test_getitem_periodindex(self):
|
| 39 |
+
rng = period_range("1/1/2000", periods=5)
|
| 40 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((10, 5)), columns=rng)
|
| 41 |
+
|
| 42 |
+
ts = df[rng[0]]
|
| 43 |
+
tm.assert_series_equal(ts, df.iloc[:, 0])
|
| 44 |
+
|
| 45 |
+
ts = df["1/1/2000"]
|
| 46 |
+
tm.assert_series_equal(ts, df.iloc[:, 0])
|
| 47 |
+
|
| 48 |
+
def test_getitem_list_of_labels_categoricalindex_cols(self):
|
| 49 |
+
# GH#16115
|
| 50 |
+
cats = Categorical([Timestamp("12-31-1999"), Timestamp("12-31-2000")])
|
| 51 |
+
|
| 52 |
+
expected = DataFrame([[1, 0], [0, 1]], dtype="bool", index=[0, 1], columns=cats)
|
| 53 |
+
dummies = get_dummies(cats)
|
| 54 |
+
result = dummies[list(dummies.columns)]
|
| 55 |
+
tm.assert_frame_equal(result, expected)
|
| 56 |
+
|
| 57 |
+
def test_getitem_sparse_column_return_type_and_dtype(self):
|
| 58 |
+
# https://github.com/pandas-dev/pandas/issues/23559
|
| 59 |
+
data = SparseArray([0, 1])
|
| 60 |
+
df = DataFrame({"A": data})
|
| 61 |
+
expected = Series(data, name="A")
|
| 62 |
+
result = df["A"]
|
| 63 |
+
tm.assert_series_equal(result, expected)
|
| 64 |
+
|
| 65 |
+
# Also check iloc and loc while we're here
|
| 66 |
+
result = df.iloc[:, 0]
|
| 67 |
+
tm.assert_series_equal(result, expected)
|
| 68 |
+
|
| 69 |
+
result = df.loc[:, "A"]
|
| 70 |
+
tm.assert_series_equal(result, expected)
|
| 71 |
+
|
| 72 |
+
def test_getitem_string_columns(self):
|
| 73 |
+
# GH#46185
|
| 74 |
+
df = DataFrame([[1, 2]], columns=Index(["A", "B"], dtype="string"))
|
| 75 |
+
result = df.A
|
| 76 |
+
expected = df["A"]
|
| 77 |
+
tm.assert_series_equal(result, expected)
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
class TestGetitemListLike:
|
| 81 |
+
def test_getitem_list_missing_key(self):
|
| 82 |
+
# GH#13822, incorrect error string with non-unique columns when missing
|
| 83 |
+
# column is accessed
|
| 84 |
+
df = DataFrame({"x": [1.0], "y": [2.0], "z": [3.0]})
|
| 85 |
+
df.columns = ["x", "x", "z"]
|
| 86 |
+
|
| 87 |
+
# Check that we get the correct value in the KeyError
|
| 88 |
+
with pytest.raises(KeyError, match=r"\['y'\] not in index"):
|
| 89 |
+
df[["x", "y", "z"]]
|
| 90 |
+
|
| 91 |
+
def test_getitem_list_duplicates(self):
|
| 92 |
+
# GH#1943
|
| 93 |
+
df = DataFrame(
|
| 94 |
+
np.random.default_rng(2).standard_normal((4, 4)), columns=list("AABC")
|
| 95 |
+
)
|
| 96 |
+
df.columns.name = "foo"
|
| 97 |
+
|
| 98 |
+
result = df[["B", "C"]]
|
| 99 |
+
assert result.columns.name == "foo"
|
| 100 |
+
|
| 101 |
+
expected = df.iloc[:, 2:]
|
| 102 |
+
tm.assert_frame_equal(result, expected)
|
| 103 |
+
|
| 104 |
+
def test_getitem_dupe_cols(self):
|
| 105 |
+
df = DataFrame([[1, 2, 3], [4, 5, 6]], columns=["a", "a", "b"])
|
| 106 |
+
msg = "\"None of [Index(['baf'], dtype="
|
| 107 |
+
with pytest.raises(KeyError, match=re.escape(msg)):
|
| 108 |
+
df[["baf"]]
|
| 109 |
+
|
| 110 |
+
@pytest.mark.parametrize(
|
| 111 |
+
"idx_type",
|
| 112 |
+
[
|
| 113 |
+
list,
|
| 114 |
+
iter,
|
| 115 |
+
Index,
|
| 116 |
+
set,
|
| 117 |
+
lambda keys: dict(zip(keys, range(len(keys)))),
|
| 118 |
+
lambda keys: dict(zip(keys, range(len(keys)))).keys(),
|
| 119 |
+
],
|
| 120 |
+
ids=["list", "iter", "Index", "set", "dict", "dict_keys"],
|
| 121 |
+
)
|
| 122 |
+
@pytest.mark.parametrize("levels", [1, 2])
|
| 123 |
+
def test_getitem_listlike(self, idx_type, levels, float_frame):
|
| 124 |
+
# GH#21294
|
| 125 |
+
|
| 126 |
+
if levels == 1:
|
| 127 |
+
frame, missing = float_frame, "food"
|
| 128 |
+
else:
|
| 129 |
+
# MultiIndex columns
|
| 130 |
+
frame = DataFrame(
|
| 131 |
+
np.random.default_rng(2).standard_normal((8, 3)),
|
| 132 |
+
columns=Index(
|
| 133 |
+
[("foo", "bar"), ("baz", "qux"), ("peek", "aboo")],
|
| 134 |
+
name=("sth", "sth2"),
|
| 135 |
+
),
|
| 136 |
+
)
|
| 137 |
+
missing = ("good", "food")
|
| 138 |
+
|
| 139 |
+
keys = [frame.columns[1], frame.columns[0]]
|
| 140 |
+
idx = idx_type(keys)
|
| 141 |
+
idx_check = list(idx_type(keys))
|
| 142 |
+
|
| 143 |
+
if isinstance(idx, (set, dict)):
|
| 144 |
+
with pytest.raises(TypeError, match="as an indexer is not supported"):
|
| 145 |
+
frame[idx]
|
| 146 |
+
|
| 147 |
+
return
|
| 148 |
+
else:
|
| 149 |
+
result = frame[idx]
|
| 150 |
+
|
| 151 |
+
expected = frame.loc[:, idx_check]
|
| 152 |
+
expected.columns.names = frame.columns.names
|
| 153 |
+
|
| 154 |
+
tm.assert_frame_equal(result, expected)
|
| 155 |
+
|
| 156 |
+
idx = idx_type(keys + [missing])
|
| 157 |
+
with pytest.raises(KeyError, match="not in index"):
|
| 158 |
+
frame[idx]
|
| 159 |
+
|
| 160 |
+
def test_getitem_iloc_generator(self):
|
| 161 |
+
# GH#39614
|
| 162 |
+
df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
|
| 163 |
+
indexer = (x for x in [1, 2])
|
| 164 |
+
result = df.iloc[indexer]
|
| 165 |
+
expected = DataFrame({"a": [2, 3], "b": [5, 6]}, index=[1, 2])
|
| 166 |
+
tm.assert_frame_equal(result, expected)
|
| 167 |
+
|
| 168 |
+
def test_getitem_iloc_two_dimensional_generator(self):
|
| 169 |
+
df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
|
| 170 |
+
indexer = (x for x in [1, 2])
|
| 171 |
+
result = df.iloc[indexer, 1]
|
| 172 |
+
expected = Series([5, 6], name="b", index=[1, 2])
|
| 173 |
+
tm.assert_series_equal(result, expected)
|
| 174 |
+
|
| 175 |
+
def test_getitem_iloc_dateoffset_days(self):
|
| 176 |
+
# GH 46671
|
| 177 |
+
df = DataFrame(
|
| 178 |
+
list(range(10)),
|
| 179 |
+
index=date_range("01-01-2022", periods=10, freq=DateOffset(days=1)),
|
| 180 |
+
)
|
| 181 |
+
result = df.loc["2022-01-01":"2022-01-03"]
|
| 182 |
+
expected = DataFrame(
|
| 183 |
+
[0, 1, 2],
|
| 184 |
+
index=DatetimeIndex(
|
| 185 |
+
["2022-01-01", "2022-01-02", "2022-01-03"],
|
| 186 |
+
dtype="datetime64[ns]",
|
| 187 |
+
freq=DateOffset(days=1),
|
| 188 |
+
),
|
| 189 |
+
)
|
| 190 |
+
tm.assert_frame_equal(result, expected)
|
| 191 |
+
|
| 192 |
+
df = DataFrame(
|
| 193 |
+
list(range(10)),
|
| 194 |
+
index=date_range(
|
| 195 |
+
"01-01-2022", periods=10, freq=DateOffset(days=1, hours=2)
|
| 196 |
+
),
|
| 197 |
+
)
|
| 198 |
+
result = df.loc["2022-01-01":"2022-01-03"]
|
| 199 |
+
expected = DataFrame(
|
| 200 |
+
[0, 1, 2],
|
| 201 |
+
index=DatetimeIndex(
|
| 202 |
+
["2022-01-01 00:00:00", "2022-01-02 02:00:00", "2022-01-03 04:00:00"],
|
| 203 |
+
dtype="datetime64[ns]",
|
| 204 |
+
freq=DateOffset(days=1, hours=2),
|
| 205 |
+
),
|
| 206 |
+
)
|
| 207 |
+
tm.assert_frame_equal(result, expected)
|
| 208 |
+
|
| 209 |
+
df = DataFrame(
|
| 210 |
+
list(range(10)),
|
| 211 |
+
index=date_range("01-01-2022", periods=10, freq=DateOffset(minutes=3)),
|
| 212 |
+
)
|
| 213 |
+
result = df.loc["2022-01-01":"2022-01-03"]
|
| 214 |
+
tm.assert_frame_equal(result, df)
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
class TestGetitemCallable:
|
| 218 |
+
def test_getitem_callable(self, float_frame):
|
| 219 |
+
# GH#12533
|
| 220 |
+
result = float_frame[lambda x: "A"]
|
| 221 |
+
expected = float_frame.loc[:, "A"]
|
| 222 |
+
tm.assert_series_equal(result, expected)
|
| 223 |
+
|
| 224 |
+
result = float_frame[lambda x: ["A", "B"]]
|
| 225 |
+
expected = float_frame.loc[:, ["A", "B"]]
|
| 226 |
+
tm.assert_frame_equal(result, float_frame.loc[:, ["A", "B"]])
|
| 227 |
+
|
| 228 |
+
df = float_frame[:3]
|
| 229 |
+
result = df[lambda x: [True, False, True]]
|
| 230 |
+
expected = float_frame.iloc[[0, 2], :]
|
| 231 |
+
tm.assert_frame_equal(result, expected)
|
| 232 |
+
|
| 233 |
+
def test_loc_multiindex_columns_one_level(self):
|
| 234 |
+
# GH#29749
|
| 235 |
+
df = DataFrame([[1, 2]], columns=[["a", "b"]])
|
| 236 |
+
expected = DataFrame([1], columns=[["a"]])
|
| 237 |
+
|
| 238 |
+
result = df["a"]
|
| 239 |
+
tm.assert_frame_equal(result, expected)
|
| 240 |
+
|
| 241 |
+
result = df.loc[:, "a"]
|
| 242 |
+
tm.assert_frame_equal(result, expected)
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
class TestGetitemBooleanMask:
|
| 246 |
+
def test_getitem_bool_mask_categorical_index(self):
|
| 247 |
+
df3 = DataFrame(
|
| 248 |
+
{
|
| 249 |
+
"A": np.arange(6, dtype="int64"),
|
| 250 |
+
},
|
| 251 |
+
index=CategoricalIndex(
|
| 252 |
+
[1, 1, 2, 1, 3, 2],
|
| 253 |
+
dtype=CategoricalDtype([3, 2, 1], ordered=True),
|
| 254 |
+
name="B",
|
| 255 |
+
),
|
| 256 |
+
)
|
| 257 |
+
df4 = DataFrame(
|
| 258 |
+
{
|
| 259 |
+
"A": np.arange(6, dtype="int64"),
|
| 260 |
+
},
|
| 261 |
+
index=CategoricalIndex(
|
| 262 |
+
[1, 1, 2, 1, 3, 2],
|
| 263 |
+
dtype=CategoricalDtype([3, 2, 1], ordered=False),
|
| 264 |
+
name="B",
|
| 265 |
+
),
|
| 266 |
+
)
|
| 267 |
+
|
| 268 |
+
result = df3[df3.index == "a"]
|
| 269 |
+
expected = df3.iloc[[]]
|
| 270 |
+
tm.assert_frame_equal(result, expected)
|
| 271 |
+
|
| 272 |
+
result = df4[df4.index == "a"]
|
| 273 |
+
expected = df4.iloc[[]]
|
| 274 |
+
tm.assert_frame_equal(result, expected)
|
| 275 |
+
|
| 276 |
+
result = df3[df3.index == 1]
|
| 277 |
+
expected = df3.iloc[[0, 1, 3]]
|
| 278 |
+
tm.assert_frame_equal(result, expected)
|
| 279 |
+
|
| 280 |
+
result = df4[df4.index == 1]
|
| 281 |
+
expected = df4.iloc[[0, 1, 3]]
|
| 282 |
+
tm.assert_frame_equal(result, expected)
|
| 283 |
+
|
| 284 |
+
# since we have an ordered categorical
|
| 285 |
+
|
| 286 |
+
# CategoricalIndex([1, 1, 2, 1, 3, 2],
|
| 287 |
+
# categories=[3, 2, 1],
|
| 288 |
+
# ordered=True,
|
| 289 |
+
# name='B')
|
| 290 |
+
result = df3[df3.index < 2]
|
| 291 |
+
expected = df3.iloc[[4]]
|
| 292 |
+
tm.assert_frame_equal(result, expected)
|
| 293 |
+
|
| 294 |
+
result = df3[df3.index > 1]
|
| 295 |
+
expected = df3.iloc[[]]
|
| 296 |
+
tm.assert_frame_equal(result, expected)
|
| 297 |
+
|
| 298 |
+
# unordered
|
| 299 |
+
# cannot be compared
|
| 300 |
+
|
| 301 |
+
# CategoricalIndex([1, 1, 2, 1, 3, 2],
|
| 302 |
+
# categories=[3, 2, 1],
|
| 303 |
+
# ordered=False,
|
| 304 |
+
# name='B')
|
| 305 |
+
msg = "Unordered Categoricals can only compare equality or not"
|
| 306 |
+
with pytest.raises(TypeError, match=msg):
|
| 307 |
+
df4[df4.index < 2]
|
| 308 |
+
with pytest.raises(TypeError, match=msg):
|
| 309 |
+
df4[df4.index > 1]
|
| 310 |
+
|
| 311 |
+
@pytest.mark.parametrize(
|
| 312 |
+
"data1,data2,expected_data",
|
| 313 |
+
(
|
| 314 |
+
(
|
| 315 |
+
[[1, 2], [3, 4]],
|
| 316 |
+
[[0.5, 6], [7, 8]],
|
| 317 |
+
[[np.nan, 3.0], [np.nan, 4.0], [np.nan, 7.0], [6.0, 8.0]],
|
| 318 |
+
),
|
| 319 |
+
(
|
| 320 |
+
[[1, 2], [3, 4]],
|
| 321 |
+
[[5, 6], [7, 8]],
|
| 322 |
+
[[np.nan, 3.0], [np.nan, 4.0], [5, 7], [6, 8]],
|
| 323 |
+
),
|
| 324 |
+
),
|
| 325 |
+
)
|
| 326 |
+
def test_getitem_bool_mask_duplicate_columns_mixed_dtypes(
|
| 327 |
+
self,
|
| 328 |
+
data1,
|
| 329 |
+
data2,
|
| 330 |
+
expected_data,
|
| 331 |
+
):
|
| 332 |
+
# GH#31954
|
| 333 |
+
|
| 334 |
+
df1 = DataFrame(np.array(data1))
|
| 335 |
+
df2 = DataFrame(np.array(data2))
|
| 336 |
+
df = concat([df1, df2], axis=1)
|
| 337 |
+
|
| 338 |
+
result = df[df > 2]
|
| 339 |
+
|
| 340 |
+
exdict = {i: np.array(col) for i, col in enumerate(expected_data)}
|
| 341 |
+
expected = DataFrame(exdict).rename(columns={2: 0, 3: 1})
|
| 342 |
+
tm.assert_frame_equal(result, expected)
|
| 343 |
+
|
| 344 |
+
@pytest.fixture
|
| 345 |
+
def df_dup_cols(self):
|
| 346 |
+
dups = ["A", "A", "C", "D"]
|
| 347 |
+
df = DataFrame(np.arange(12).reshape(3, 4), columns=dups, dtype="float64")
|
| 348 |
+
return df
|
| 349 |
+
|
| 350 |
+
def test_getitem_boolean_frame_unaligned_with_duplicate_columns(self, df_dup_cols):
|
| 351 |
+
# `df.A > 6` is a DataFrame with a different shape from df
|
| 352 |
+
|
| 353 |
+
# boolean with the duplicate raises
|
| 354 |
+
df = df_dup_cols
|
| 355 |
+
msg = "cannot reindex on an axis with duplicate labels"
|
| 356 |
+
with pytest.raises(ValueError, match=msg):
|
| 357 |
+
df[df.A > 6]
|
| 358 |
+
|
| 359 |
+
def test_getitem_boolean_series_with_duplicate_columns(self, df_dup_cols):
|
| 360 |
+
# boolean indexing
|
| 361 |
+
# GH#4879
|
| 362 |
+
df = DataFrame(
|
| 363 |
+
np.arange(12).reshape(3, 4), columns=["A", "B", "C", "D"], dtype="float64"
|
| 364 |
+
)
|
| 365 |
+
expected = df[df.C > 6]
|
| 366 |
+
expected.columns = df_dup_cols.columns
|
| 367 |
+
|
| 368 |
+
df = df_dup_cols
|
| 369 |
+
result = df[df.C > 6]
|
| 370 |
+
|
| 371 |
+
tm.assert_frame_equal(result, expected)
|
| 372 |
+
|
| 373 |
+
def test_getitem_boolean_frame_with_duplicate_columns(self, df_dup_cols):
|
| 374 |
+
# where
|
| 375 |
+
df = DataFrame(
|
| 376 |
+
np.arange(12).reshape(3, 4), columns=["A", "B", "C", "D"], dtype="float64"
|
| 377 |
+
)
|
| 378 |
+
# `df > 6` is a DataFrame with the same shape+alignment as df
|
| 379 |
+
expected = df[df > 6]
|
| 380 |
+
expected.columns = df_dup_cols.columns
|
| 381 |
+
|
| 382 |
+
df = df_dup_cols
|
| 383 |
+
result = df[df > 6]
|
| 384 |
+
|
| 385 |
+
tm.assert_frame_equal(result, expected)
|
| 386 |
+
|
| 387 |
+
def test_getitem_empty_frame_with_boolean(self):
|
| 388 |
+
# Test for issue GH#11859
|
| 389 |
+
|
| 390 |
+
df = DataFrame()
|
| 391 |
+
df2 = df[df > 0]
|
| 392 |
+
tm.assert_frame_equal(df, df2)
|
| 393 |
+
|
| 394 |
+
def test_getitem_returns_view_when_column_is_unique_in_df(
|
| 395 |
+
self, using_copy_on_write, warn_copy_on_write
|
| 396 |
+
):
|
| 397 |
+
# GH#45316
|
| 398 |
+
df = DataFrame([[1, 2, 3], [4, 5, 6]], columns=["a", "a", "b"])
|
| 399 |
+
df_orig = df.copy()
|
| 400 |
+
view = df["b"]
|
| 401 |
+
with tm.assert_cow_warning(warn_copy_on_write):
|
| 402 |
+
view.loc[:] = 100
|
| 403 |
+
if using_copy_on_write:
|
| 404 |
+
expected = df_orig
|
| 405 |
+
else:
|
| 406 |
+
expected = DataFrame([[1, 2, 100], [4, 5, 100]], columns=["a", "a", "b"])
|
| 407 |
+
tm.assert_frame_equal(df, expected)
|
| 408 |
+
|
| 409 |
+
def test_getitem_frozenset_unique_in_column(self):
|
| 410 |
+
# GH#41062
|
| 411 |
+
df = DataFrame([[1, 2, 3, 4]], columns=[frozenset(["KEY"]), "B", "C", "C"])
|
| 412 |
+
result = df[frozenset(["KEY"])]
|
| 413 |
+
expected = Series([1], name=frozenset(["KEY"]))
|
| 414 |
+
tm.assert_series_equal(result, expected)
|
| 415 |
+
|
| 416 |
+
|
| 417 |
+
class TestGetitemSlice:
|
| 418 |
+
def test_getitem_slice_float64(self, frame_or_series):
|
| 419 |
+
values = np.arange(10.0, 50.0, 2)
|
| 420 |
+
index = Index(values)
|
| 421 |
+
|
| 422 |
+
start, end = values[[5, 15]]
|
| 423 |
+
|
| 424 |
+
data = np.random.default_rng(2).standard_normal((20, 3))
|
| 425 |
+
if frame_or_series is not DataFrame:
|
| 426 |
+
data = data[:, 0]
|
| 427 |
+
|
| 428 |
+
obj = frame_or_series(data, index=index)
|
| 429 |
+
|
| 430 |
+
result = obj[start:end]
|
| 431 |
+
expected = obj.iloc[5:16]
|
| 432 |
+
tm.assert_equal(result, expected)
|
| 433 |
+
|
| 434 |
+
result = obj.loc[start:end]
|
| 435 |
+
tm.assert_equal(result, expected)
|
| 436 |
+
|
| 437 |
+
def test_getitem_datetime_slice(self):
|
| 438 |
+
# GH#43223
|
| 439 |
+
df = DataFrame(
|
| 440 |
+
{"a": 0},
|
| 441 |
+
index=DatetimeIndex(
|
| 442 |
+
[
|
| 443 |
+
"11.01.2011 22:00",
|
| 444 |
+
"11.01.2011 23:00",
|
| 445 |
+
"12.01.2011 00:00",
|
| 446 |
+
"2011-01-13 00:00",
|
| 447 |
+
]
|
| 448 |
+
),
|
| 449 |
+
)
|
| 450 |
+
with pytest.raises(
|
| 451 |
+
KeyError, match="Value based partial slicing on non-monotonic"
|
| 452 |
+
):
|
| 453 |
+
df["2011-01-01":"2011-11-01"]
|
| 454 |
+
|
| 455 |
+
def test_getitem_slice_same_dim_only_one_axis(self):
|
| 456 |
+
# GH#54622
|
| 457 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((10, 8)))
|
| 458 |
+
result = df.iloc[(slice(None, None, 2),)]
|
| 459 |
+
assert result.shape == (5, 8)
|
| 460 |
+
expected = df.iloc[slice(None, None, 2), slice(None)]
|
| 461 |
+
tm.assert_frame_equal(result, expected)
|
| 462 |
+
|
| 463 |
+
|
| 464 |
+
class TestGetitemDeprecatedIndexers:
|
| 465 |
+
@pytest.mark.parametrize("key", [{"a", "b"}, {"a": "a"}])
|
| 466 |
+
def test_getitem_dict_and_set_deprecated(self, key):
|
| 467 |
+
# GH#42825 enforced in 2.0
|
| 468 |
+
df = DataFrame(
|
| 469 |
+
[[1, 2], [3, 4]], columns=MultiIndex.from_tuples([("a", 1), ("b", 2)])
|
| 470 |
+
)
|
| 471 |
+
with pytest.raises(TypeError, match="as an indexer is not supported"):
|
| 472 |
+
df[key]
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/test_indexing.py
ADDED
|
@@ -0,0 +1,2024 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from collections import namedtuple
|
| 2 |
+
from datetime import (
|
| 3 |
+
datetime,
|
| 4 |
+
timedelta,
|
| 5 |
+
)
|
| 6 |
+
from decimal import Decimal
|
| 7 |
+
import re
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
import pytest
|
| 11 |
+
|
| 12 |
+
from pandas._libs import iNaT
|
| 13 |
+
from pandas.errors import (
|
| 14 |
+
InvalidIndexError,
|
| 15 |
+
PerformanceWarning,
|
| 16 |
+
SettingWithCopyError,
|
| 17 |
+
)
|
| 18 |
+
import pandas.util._test_decorators as td
|
| 19 |
+
|
| 20 |
+
from pandas.core.dtypes.common import is_integer
|
| 21 |
+
|
| 22 |
+
import pandas as pd
|
| 23 |
+
from pandas import (
|
| 24 |
+
Categorical,
|
| 25 |
+
DataFrame,
|
| 26 |
+
DatetimeIndex,
|
| 27 |
+
Index,
|
| 28 |
+
MultiIndex,
|
| 29 |
+
Series,
|
| 30 |
+
Timestamp,
|
| 31 |
+
date_range,
|
| 32 |
+
isna,
|
| 33 |
+
notna,
|
| 34 |
+
to_datetime,
|
| 35 |
+
)
|
| 36 |
+
import pandas._testing as tm
|
| 37 |
+
|
| 38 |
+
# We pass through a TypeError raised by numpy
|
| 39 |
+
_slice_msg = "slice indices must be integers or None or have an __index__ method"
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
class TestDataFrameIndexing:
|
| 43 |
+
def test_getitem(self, float_frame):
|
| 44 |
+
# Slicing
|
| 45 |
+
sl = float_frame[:20]
|
| 46 |
+
assert len(sl.index) == 20
|
| 47 |
+
|
| 48 |
+
# Column access
|
| 49 |
+
for _, series in sl.items():
|
| 50 |
+
assert len(series.index) == 20
|
| 51 |
+
tm.assert_index_equal(series.index, sl.index)
|
| 52 |
+
|
| 53 |
+
for key, _ in float_frame._series.items():
|
| 54 |
+
assert float_frame[key] is not None
|
| 55 |
+
|
| 56 |
+
assert "random" not in float_frame
|
| 57 |
+
with pytest.raises(KeyError, match="random"):
|
| 58 |
+
float_frame["random"]
|
| 59 |
+
|
| 60 |
+
def test_getitem_numeric_should_not_fallback_to_positional(self, any_numeric_dtype):
|
| 61 |
+
# GH51053
|
| 62 |
+
dtype = any_numeric_dtype
|
| 63 |
+
idx = Index([1, 0, 1], dtype=dtype)
|
| 64 |
+
df = DataFrame([[1, 2, 3], [4, 5, 6]], columns=idx)
|
| 65 |
+
result = df[1]
|
| 66 |
+
expected = DataFrame([[1, 3], [4, 6]], columns=Index([1, 1], dtype=dtype))
|
| 67 |
+
tm.assert_frame_equal(result, expected, check_exact=True)
|
| 68 |
+
|
| 69 |
+
def test_getitem2(self, float_frame):
|
| 70 |
+
df = float_frame.copy()
|
| 71 |
+
df["$10"] = np.random.default_rng(2).standard_normal(len(df))
|
| 72 |
+
|
| 73 |
+
ad = np.random.default_rng(2).standard_normal(len(df))
|
| 74 |
+
df["@awesome_domain"] = ad
|
| 75 |
+
|
| 76 |
+
with pytest.raises(KeyError, match=re.escape("'df[\"$10\"]'")):
|
| 77 |
+
df.__getitem__('df["$10"]')
|
| 78 |
+
|
| 79 |
+
res = df["@awesome_domain"]
|
| 80 |
+
tm.assert_numpy_array_equal(ad, res.values)
|
| 81 |
+
|
| 82 |
+
def test_setitem_numeric_should_not_fallback_to_positional(self, any_numeric_dtype):
|
| 83 |
+
# GH51053
|
| 84 |
+
dtype = any_numeric_dtype
|
| 85 |
+
idx = Index([1, 0, 1], dtype=dtype)
|
| 86 |
+
df = DataFrame([[1, 2, 3], [4, 5, 6]], columns=idx)
|
| 87 |
+
df[1] = 10
|
| 88 |
+
expected = DataFrame([[10, 2, 10], [10, 5, 10]], columns=idx)
|
| 89 |
+
tm.assert_frame_equal(df, expected, check_exact=True)
|
| 90 |
+
|
| 91 |
+
def test_setitem_list(self, float_frame):
|
| 92 |
+
float_frame["E"] = "foo"
|
| 93 |
+
data = float_frame[["A", "B"]]
|
| 94 |
+
float_frame[["B", "A"]] = data
|
| 95 |
+
|
| 96 |
+
tm.assert_series_equal(float_frame["B"], data["A"], check_names=False)
|
| 97 |
+
tm.assert_series_equal(float_frame["A"], data["B"], check_names=False)
|
| 98 |
+
|
| 99 |
+
msg = "Columns must be same length as key"
|
| 100 |
+
with pytest.raises(ValueError, match=msg):
|
| 101 |
+
data[["A"]] = float_frame[["A", "B"]]
|
| 102 |
+
newcolumndata = range(len(data.index) - 1)
|
| 103 |
+
msg = (
|
| 104 |
+
rf"Length of values \({len(newcolumndata)}\) "
|
| 105 |
+
rf"does not match length of index \({len(data)}\)"
|
| 106 |
+
)
|
| 107 |
+
with pytest.raises(ValueError, match=msg):
|
| 108 |
+
data["A"] = newcolumndata
|
| 109 |
+
|
| 110 |
+
def test_setitem_list2(self):
|
| 111 |
+
df = DataFrame(0, index=range(3), columns=["tt1", "tt2"], dtype=int)
|
| 112 |
+
df.loc[1, ["tt1", "tt2"]] = [1, 2]
|
| 113 |
+
|
| 114 |
+
result = df.loc[df.index[1], ["tt1", "tt2"]]
|
| 115 |
+
expected = Series([1, 2], df.columns, dtype=int, name=1)
|
| 116 |
+
tm.assert_series_equal(result, expected)
|
| 117 |
+
|
| 118 |
+
df["tt1"] = df["tt2"] = "0"
|
| 119 |
+
df.loc[df.index[1], ["tt1", "tt2"]] = ["1", "2"]
|
| 120 |
+
result = df.loc[df.index[1], ["tt1", "tt2"]]
|
| 121 |
+
expected = Series(["1", "2"], df.columns, name=1)
|
| 122 |
+
tm.assert_series_equal(result, expected)
|
| 123 |
+
|
| 124 |
+
def test_getitem_boolean(self, mixed_float_frame, mixed_int_frame, datetime_frame):
|
| 125 |
+
# boolean indexing
|
| 126 |
+
d = datetime_frame.index[10]
|
| 127 |
+
indexer = datetime_frame.index > d
|
| 128 |
+
indexer_obj = indexer.astype(object)
|
| 129 |
+
|
| 130 |
+
subindex = datetime_frame.index[indexer]
|
| 131 |
+
subframe = datetime_frame[indexer]
|
| 132 |
+
|
| 133 |
+
tm.assert_index_equal(subindex, subframe.index)
|
| 134 |
+
with pytest.raises(ValueError, match="Item wrong length"):
|
| 135 |
+
datetime_frame[indexer[:-1]]
|
| 136 |
+
|
| 137 |
+
subframe_obj = datetime_frame[indexer_obj]
|
| 138 |
+
tm.assert_frame_equal(subframe_obj, subframe)
|
| 139 |
+
|
| 140 |
+
with pytest.raises(ValueError, match="Boolean array expected"):
|
| 141 |
+
datetime_frame[datetime_frame]
|
| 142 |
+
|
| 143 |
+
# test that Series work
|
| 144 |
+
indexer_obj = Series(indexer_obj, datetime_frame.index)
|
| 145 |
+
|
| 146 |
+
subframe_obj = datetime_frame[indexer_obj]
|
| 147 |
+
tm.assert_frame_equal(subframe_obj, subframe)
|
| 148 |
+
|
| 149 |
+
# test that Series indexers reindex
|
| 150 |
+
# we are producing a warning that since the passed boolean
|
| 151 |
+
# key is not the same as the given index, we will reindex
|
| 152 |
+
# not sure this is really necessary
|
| 153 |
+
with tm.assert_produces_warning(UserWarning):
|
| 154 |
+
indexer_obj = indexer_obj.reindex(datetime_frame.index[::-1])
|
| 155 |
+
subframe_obj = datetime_frame[indexer_obj]
|
| 156 |
+
tm.assert_frame_equal(subframe_obj, subframe)
|
| 157 |
+
|
| 158 |
+
# test df[df > 0]
|
| 159 |
+
for df in [
|
| 160 |
+
datetime_frame,
|
| 161 |
+
mixed_float_frame,
|
| 162 |
+
mixed_int_frame,
|
| 163 |
+
]:
|
| 164 |
+
data = df._get_numeric_data()
|
| 165 |
+
bif = df[df > 0]
|
| 166 |
+
bifw = DataFrame(
|
| 167 |
+
{c: np.where(data[c] > 0, data[c], np.nan) for c in data.columns},
|
| 168 |
+
index=data.index,
|
| 169 |
+
columns=data.columns,
|
| 170 |
+
)
|
| 171 |
+
|
| 172 |
+
# add back other columns to compare
|
| 173 |
+
for c in df.columns:
|
| 174 |
+
if c not in bifw:
|
| 175 |
+
bifw[c] = df[c]
|
| 176 |
+
bifw = bifw.reindex(columns=df.columns)
|
| 177 |
+
|
| 178 |
+
tm.assert_frame_equal(bif, bifw, check_dtype=False)
|
| 179 |
+
for c in df.columns:
|
| 180 |
+
if bif[c].dtype != bifw[c].dtype:
|
| 181 |
+
assert bif[c].dtype == df[c].dtype
|
| 182 |
+
|
| 183 |
+
def test_getitem_boolean_casting(self, datetime_frame):
|
| 184 |
+
# don't upcast if we don't need to
|
| 185 |
+
df = datetime_frame.copy()
|
| 186 |
+
df["E"] = 1
|
| 187 |
+
df["E"] = df["E"].astype("int32")
|
| 188 |
+
df["E1"] = df["E"].copy()
|
| 189 |
+
df["F"] = 1
|
| 190 |
+
df["F"] = df["F"].astype("int64")
|
| 191 |
+
df["F1"] = df["F"].copy()
|
| 192 |
+
|
| 193 |
+
casted = df[df > 0]
|
| 194 |
+
result = casted.dtypes
|
| 195 |
+
expected = Series(
|
| 196 |
+
[np.dtype("float64")] * 4
|
| 197 |
+
+ [np.dtype("int32")] * 2
|
| 198 |
+
+ [np.dtype("int64")] * 2,
|
| 199 |
+
index=["A", "B", "C", "D", "E", "E1", "F", "F1"],
|
| 200 |
+
)
|
| 201 |
+
tm.assert_series_equal(result, expected)
|
| 202 |
+
|
| 203 |
+
# int block splitting
|
| 204 |
+
df.loc[df.index[1:3], ["E1", "F1"]] = 0
|
| 205 |
+
casted = df[df > 0]
|
| 206 |
+
result = casted.dtypes
|
| 207 |
+
expected = Series(
|
| 208 |
+
[np.dtype("float64")] * 4
|
| 209 |
+
+ [np.dtype("int32")]
|
| 210 |
+
+ [np.dtype("float64")]
|
| 211 |
+
+ [np.dtype("int64")]
|
| 212 |
+
+ [np.dtype("float64")],
|
| 213 |
+
index=["A", "B", "C", "D", "E", "E1", "F", "F1"],
|
| 214 |
+
)
|
| 215 |
+
tm.assert_series_equal(result, expected)
|
| 216 |
+
|
| 217 |
+
@pytest.mark.parametrize(
|
| 218 |
+
"lst", [[True, False, True], [True, True, True], [False, False, False]]
|
| 219 |
+
)
|
| 220 |
+
def test_getitem_boolean_list(self, lst):
|
| 221 |
+
df = DataFrame(np.arange(12).reshape(3, 4))
|
| 222 |
+
result = df[lst]
|
| 223 |
+
expected = df.loc[df.index[lst]]
|
| 224 |
+
tm.assert_frame_equal(result, expected)
|
| 225 |
+
|
| 226 |
+
def test_getitem_boolean_iadd(self):
|
| 227 |
+
arr = np.random.default_rng(2).standard_normal((5, 5))
|
| 228 |
+
|
| 229 |
+
df = DataFrame(arr.copy(), columns=["A", "B", "C", "D", "E"])
|
| 230 |
+
|
| 231 |
+
df[df < 0] += 1
|
| 232 |
+
arr[arr < 0] += 1
|
| 233 |
+
|
| 234 |
+
tm.assert_almost_equal(df.values, arr)
|
| 235 |
+
|
| 236 |
+
def test_boolean_index_empty_corner(self):
|
| 237 |
+
# #2096
|
| 238 |
+
blah = DataFrame(np.empty([0, 1]), columns=["A"], index=DatetimeIndex([]))
|
| 239 |
+
|
| 240 |
+
# both of these should succeed trivially
|
| 241 |
+
k = np.array([], bool)
|
| 242 |
+
|
| 243 |
+
blah[k]
|
| 244 |
+
blah[k] = 0
|
| 245 |
+
|
| 246 |
+
def test_getitem_ix_mixed_integer(self):
|
| 247 |
+
df = DataFrame(
|
| 248 |
+
np.random.default_rng(2).standard_normal((4, 3)),
|
| 249 |
+
index=[1, 10, "C", "E"],
|
| 250 |
+
columns=[1, 2, 3],
|
| 251 |
+
)
|
| 252 |
+
|
| 253 |
+
result = df.iloc[:-1]
|
| 254 |
+
expected = df.loc[df.index[:-1]]
|
| 255 |
+
tm.assert_frame_equal(result, expected)
|
| 256 |
+
|
| 257 |
+
result = df.loc[[1, 10]]
|
| 258 |
+
expected = df.loc[Index([1, 10])]
|
| 259 |
+
tm.assert_frame_equal(result, expected)
|
| 260 |
+
|
| 261 |
+
def test_getitem_ix_mixed_integer2(self):
|
| 262 |
+
# 11320
|
| 263 |
+
df = DataFrame(
|
| 264 |
+
{
|
| 265 |
+
"rna": (1.5, 2.2, 3.2, 4.5),
|
| 266 |
+
-1000: [11, 21, 36, 40],
|
| 267 |
+
0: [10, 22, 43, 34],
|
| 268 |
+
1000: [0, 10, 20, 30],
|
| 269 |
+
},
|
| 270 |
+
columns=["rna", -1000, 0, 1000],
|
| 271 |
+
)
|
| 272 |
+
result = df[[1000]]
|
| 273 |
+
expected = df.iloc[:, [3]]
|
| 274 |
+
tm.assert_frame_equal(result, expected)
|
| 275 |
+
result = df[[-1000]]
|
| 276 |
+
expected = df.iloc[:, [1]]
|
| 277 |
+
tm.assert_frame_equal(result, expected)
|
| 278 |
+
|
| 279 |
+
def test_getattr(self, float_frame):
|
| 280 |
+
tm.assert_series_equal(float_frame.A, float_frame["A"])
|
| 281 |
+
msg = "'DataFrame' object has no attribute 'NONEXISTENT_NAME'"
|
| 282 |
+
with pytest.raises(AttributeError, match=msg):
|
| 283 |
+
float_frame.NONEXISTENT_NAME
|
| 284 |
+
|
| 285 |
+
def test_setattr_column(self):
|
| 286 |
+
df = DataFrame({"foobar": 1}, index=range(10))
|
| 287 |
+
|
| 288 |
+
df.foobar = 5
|
| 289 |
+
assert (df.foobar == 5).all()
|
| 290 |
+
|
| 291 |
+
def test_setitem(
|
| 292 |
+
self, float_frame, using_copy_on_write, warn_copy_on_write, using_infer_string
|
| 293 |
+
):
|
| 294 |
+
# not sure what else to do here
|
| 295 |
+
series = float_frame["A"][::2]
|
| 296 |
+
float_frame["col5"] = series
|
| 297 |
+
assert "col5" in float_frame
|
| 298 |
+
|
| 299 |
+
assert len(series) == 15
|
| 300 |
+
assert len(float_frame) == 30
|
| 301 |
+
|
| 302 |
+
exp = np.ravel(np.column_stack((series.values, [np.nan] * 15)))
|
| 303 |
+
exp = Series(exp, index=float_frame.index, name="col5")
|
| 304 |
+
tm.assert_series_equal(float_frame["col5"], exp)
|
| 305 |
+
|
| 306 |
+
series = float_frame["A"]
|
| 307 |
+
float_frame["col6"] = series
|
| 308 |
+
tm.assert_series_equal(series, float_frame["col6"], check_names=False)
|
| 309 |
+
|
| 310 |
+
# set ndarray
|
| 311 |
+
arr = np.random.default_rng(2).standard_normal(len(float_frame))
|
| 312 |
+
float_frame["col9"] = arr
|
| 313 |
+
assert (float_frame["col9"] == arr).all()
|
| 314 |
+
|
| 315 |
+
float_frame["col7"] = 5
|
| 316 |
+
assert (float_frame["col7"] == 5).all()
|
| 317 |
+
|
| 318 |
+
float_frame["col0"] = 3.14
|
| 319 |
+
assert (float_frame["col0"] == 3.14).all()
|
| 320 |
+
|
| 321 |
+
float_frame["col8"] = "foo"
|
| 322 |
+
assert (float_frame["col8"] == "foo").all()
|
| 323 |
+
|
| 324 |
+
# this is partially a view (e.g. some blocks are view)
|
| 325 |
+
# so raise/warn
|
| 326 |
+
smaller = float_frame[:2]
|
| 327 |
+
|
| 328 |
+
msg = r"\nA value is trying to be set on a copy of a slice from a DataFrame"
|
| 329 |
+
if using_copy_on_write or warn_copy_on_write:
|
| 330 |
+
# With CoW, adding a new column doesn't raise a warning
|
| 331 |
+
smaller["col10"] = ["1", "2"]
|
| 332 |
+
else:
|
| 333 |
+
with pytest.raises(SettingWithCopyError, match=msg):
|
| 334 |
+
smaller["col10"] = ["1", "2"]
|
| 335 |
+
|
| 336 |
+
if using_infer_string:
|
| 337 |
+
assert smaller["col10"].dtype == "string"
|
| 338 |
+
else:
|
| 339 |
+
assert smaller["col10"].dtype == np.object_
|
| 340 |
+
assert (smaller["col10"] == ["1", "2"]).all()
|
| 341 |
+
|
| 342 |
+
def test_setitem2(self):
|
| 343 |
+
# dtype changing GH4204
|
| 344 |
+
df = DataFrame([[0, 0]])
|
| 345 |
+
df.iloc[0] = np.nan
|
| 346 |
+
expected = DataFrame([[np.nan, np.nan]])
|
| 347 |
+
tm.assert_frame_equal(df, expected)
|
| 348 |
+
|
| 349 |
+
df = DataFrame([[0, 0]])
|
| 350 |
+
df.loc[0] = np.nan
|
| 351 |
+
tm.assert_frame_equal(df, expected)
|
| 352 |
+
|
| 353 |
+
def test_setitem_boolean(self, float_frame):
|
| 354 |
+
df = float_frame.copy()
|
| 355 |
+
values = float_frame.values.copy()
|
| 356 |
+
|
| 357 |
+
df[df["A"] > 0] = 4
|
| 358 |
+
values[values[:, 0] > 0] = 4
|
| 359 |
+
tm.assert_almost_equal(df.values, values)
|
| 360 |
+
|
| 361 |
+
# test that column reindexing works
|
| 362 |
+
series = df["A"] == 4
|
| 363 |
+
series = series.reindex(df.index[::-1])
|
| 364 |
+
df[series] = 1
|
| 365 |
+
values[values[:, 0] == 4] = 1
|
| 366 |
+
tm.assert_almost_equal(df.values, values)
|
| 367 |
+
|
| 368 |
+
df[df > 0] = 5
|
| 369 |
+
values[values > 0] = 5
|
| 370 |
+
tm.assert_almost_equal(df.values, values)
|
| 371 |
+
|
| 372 |
+
df[df == 5] = 0
|
| 373 |
+
values[values == 5] = 0
|
| 374 |
+
tm.assert_almost_equal(df.values, values)
|
| 375 |
+
|
| 376 |
+
# a df that needs alignment first
|
| 377 |
+
df[df[:-1] < 0] = 2
|
| 378 |
+
np.putmask(values[:-1], values[:-1] < 0, 2)
|
| 379 |
+
tm.assert_almost_equal(df.values, values)
|
| 380 |
+
|
| 381 |
+
# indexed with same shape but rows-reversed df
|
| 382 |
+
df[df[::-1] == 2] = 3
|
| 383 |
+
values[values == 2] = 3
|
| 384 |
+
tm.assert_almost_equal(df.values, values)
|
| 385 |
+
|
| 386 |
+
msg = "Must pass DataFrame or 2-d ndarray with boolean values only"
|
| 387 |
+
with pytest.raises(TypeError, match=msg):
|
| 388 |
+
df[df * 0] = 2
|
| 389 |
+
|
| 390 |
+
# index with DataFrame
|
| 391 |
+
df_orig = df.copy()
|
| 392 |
+
mask = df > np.abs(df)
|
| 393 |
+
df[df > np.abs(df)] = np.nan
|
| 394 |
+
values = df_orig.values.copy()
|
| 395 |
+
values[mask.values] = np.nan
|
| 396 |
+
expected = DataFrame(values, index=df_orig.index, columns=df_orig.columns)
|
| 397 |
+
tm.assert_frame_equal(df, expected)
|
| 398 |
+
|
| 399 |
+
# set from DataFrame
|
| 400 |
+
df[df > np.abs(df)] = df * 2
|
| 401 |
+
np.putmask(values, mask.values, df.values * 2)
|
| 402 |
+
expected = DataFrame(values, index=df_orig.index, columns=df_orig.columns)
|
| 403 |
+
tm.assert_frame_equal(df, expected)
|
| 404 |
+
|
| 405 |
+
def test_setitem_cast(self, float_frame):
|
| 406 |
+
float_frame["D"] = float_frame["D"].astype("i8")
|
| 407 |
+
assert float_frame["D"].dtype == np.int64
|
| 408 |
+
|
| 409 |
+
# #669, should not cast?
|
| 410 |
+
# this is now set to int64, which means a replacement of the column to
|
| 411 |
+
# the value dtype (and nothing to do with the existing dtype)
|
| 412 |
+
float_frame["B"] = 0
|
| 413 |
+
assert float_frame["B"].dtype == np.int64
|
| 414 |
+
|
| 415 |
+
# cast if pass array of course
|
| 416 |
+
float_frame["B"] = np.arange(len(float_frame))
|
| 417 |
+
assert issubclass(float_frame["B"].dtype.type, np.integer)
|
| 418 |
+
|
| 419 |
+
float_frame["foo"] = "bar"
|
| 420 |
+
float_frame["foo"] = 0
|
| 421 |
+
assert float_frame["foo"].dtype == np.int64
|
| 422 |
+
|
| 423 |
+
float_frame["foo"] = "bar"
|
| 424 |
+
float_frame["foo"] = 2.5
|
| 425 |
+
assert float_frame["foo"].dtype == np.float64
|
| 426 |
+
|
| 427 |
+
float_frame["something"] = 0
|
| 428 |
+
assert float_frame["something"].dtype == np.int64
|
| 429 |
+
float_frame["something"] = 2
|
| 430 |
+
assert float_frame["something"].dtype == np.int64
|
| 431 |
+
float_frame["something"] = 2.5
|
| 432 |
+
assert float_frame["something"].dtype == np.float64
|
| 433 |
+
|
| 434 |
+
def test_setitem_corner(self, float_frame, using_infer_string):
|
| 435 |
+
# corner case
|
| 436 |
+
df = DataFrame({"B": [1.0, 2.0, 3.0], "C": ["a", "b", "c"]}, index=np.arange(3))
|
| 437 |
+
del df["B"]
|
| 438 |
+
df["B"] = [1.0, 2.0, 3.0]
|
| 439 |
+
assert "B" in df
|
| 440 |
+
assert len(df.columns) == 2
|
| 441 |
+
|
| 442 |
+
df["A"] = "beginning"
|
| 443 |
+
df["E"] = "foo"
|
| 444 |
+
df["D"] = "bar"
|
| 445 |
+
df[datetime.now()] = "date"
|
| 446 |
+
df[datetime.now()] = 5.0
|
| 447 |
+
|
| 448 |
+
# what to do when empty frame with index
|
| 449 |
+
dm = DataFrame(index=float_frame.index)
|
| 450 |
+
dm["A"] = "foo"
|
| 451 |
+
dm["B"] = "bar"
|
| 452 |
+
assert len(dm.columns) == 2
|
| 453 |
+
assert dm.values.dtype == np.object_
|
| 454 |
+
|
| 455 |
+
# upcast
|
| 456 |
+
dm["C"] = 1
|
| 457 |
+
assert dm["C"].dtype == np.int64
|
| 458 |
+
|
| 459 |
+
dm["E"] = 1.0
|
| 460 |
+
assert dm["E"].dtype == np.float64
|
| 461 |
+
|
| 462 |
+
# set existing column
|
| 463 |
+
dm["A"] = "bar"
|
| 464 |
+
assert "bar" == dm["A"].iloc[0]
|
| 465 |
+
|
| 466 |
+
dm = DataFrame(index=np.arange(3))
|
| 467 |
+
dm["A"] = 1
|
| 468 |
+
dm["foo"] = "bar"
|
| 469 |
+
del dm["foo"]
|
| 470 |
+
dm["foo"] = "bar"
|
| 471 |
+
if using_infer_string:
|
| 472 |
+
assert dm["foo"].dtype == "string"
|
| 473 |
+
else:
|
| 474 |
+
assert dm["foo"].dtype == np.object_
|
| 475 |
+
|
| 476 |
+
dm["coercible"] = ["1", "2", "3"]
|
| 477 |
+
if using_infer_string:
|
| 478 |
+
assert dm["coercible"].dtype == "string"
|
| 479 |
+
else:
|
| 480 |
+
assert dm["coercible"].dtype == np.object_
|
| 481 |
+
|
| 482 |
+
def test_setitem_corner2(self):
|
| 483 |
+
data = {
|
| 484 |
+
"title": ["foobar", "bar", "foobar"] + ["foobar"] * 17,
|
| 485 |
+
"cruft": np.random.default_rng(2).random(20),
|
| 486 |
+
}
|
| 487 |
+
|
| 488 |
+
df = DataFrame(data)
|
| 489 |
+
ix = df[df["title"] == "bar"].index
|
| 490 |
+
|
| 491 |
+
df.loc[ix, ["title"]] = "foobar"
|
| 492 |
+
df.loc[ix, ["cruft"]] = 0
|
| 493 |
+
|
| 494 |
+
assert df.loc[1, "title"] == "foobar"
|
| 495 |
+
assert df.loc[1, "cruft"] == 0
|
| 496 |
+
|
| 497 |
+
def test_setitem_ambig(self, using_infer_string):
|
| 498 |
+
# Difficulties with mixed-type data
|
| 499 |
+
# Created as float type
|
| 500 |
+
dm = DataFrame(index=range(3), columns=range(3))
|
| 501 |
+
|
| 502 |
+
coercable_series = Series([Decimal(1) for _ in range(3)], index=range(3))
|
| 503 |
+
uncoercable_series = Series(["foo", "bzr", "baz"], index=range(3))
|
| 504 |
+
|
| 505 |
+
dm[0] = np.ones(3)
|
| 506 |
+
assert len(dm.columns) == 3
|
| 507 |
+
|
| 508 |
+
dm[1] = coercable_series
|
| 509 |
+
assert len(dm.columns) == 3
|
| 510 |
+
|
| 511 |
+
dm[2] = uncoercable_series
|
| 512 |
+
assert len(dm.columns) == 3
|
| 513 |
+
if using_infer_string:
|
| 514 |
+
assert dm[2].dtype == "string"
|
| 515 |
+
else:
|
| 516 |
+
assert dm[2].dtype == np.object_
|
| 517 |
+
|
| 518 |
+
def test_setitem_None(self, float_frame, using_infer_string):
|
| 519 |
+
# GH #766
|
| 520 |
+
float_frame[None] = float_frame["A"]
|
| 521 |
+
key = None if not using_infer_string else np.nan
|
| 522 |
+
tm.assert_series_equal(
|
| 523 |
+
float_frame.iloc[:, -1], float_frame["A"], check_names=False
|
| 524 |
+
)
|
| 525 |
+
tm.assert_series_equal(
|
| 526 |
+
float_frame.loc[:, key], float_frame["A"], check_names=False
|
| 527 |
+
)
|
| 528 |
+
tm.assert_series_equal(float_frame[key], float_frame["A"], check_names=False)
|
| 529 |
+
|
| 530 |
+
def test_loc_setitem_boolean_mask_allfalse(self):
|
| 531 |
+
# GH 9596
|
| 532 |
+
df = DataFrame(
|
| 533 |
+
{"a": ["1", "2", "3"], "b": ["11", "22", "33"], "c": ["111", "222", "333"]}
|
| 534 |
+
)
|
| 535 |
+
|
| 536 |
+
result = df.copy()
|
| 537 |
+
result.loc[result.b.isna(), "a"] = result.a.copy()
|
| 538 |
+
tm.assert_frame_equal(result, df)
|
| 539 |
+
|
| 540 |
+
def test_getitem_fancy_slice_integers_step(self):
|
| 541 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((10, 5)))
|
| 542 |
+
|
| 543 |
+
# this is OK
|
| 544 |
+
df.iloc[:8:2]
|
| 545 |
+
df.iloc[:8:2] = np.nan
|
| 546 |
+
assert isna(df.iloc[:8:2]).values.all()
|
| 547 |
+
|
| 548 |
+
def test_getitem_setitem_integer_slice_keyerrors(self):
|
| 549 |
+
df = DataFrame(
|
| 550 |
+
np.random.default_rng(2).standard_normal((10, 5)), index=range(0, 20, 2)
|
| 551 |
+
)
|
| 552 |
+
|
| 553 |
+
# this is OK
|
| 554 |
+
cp = df.copy()
|
| 555 |
+
cp.iloc[4:10] = 0
|
| 556 |
+
assert (cp.iloc[4:10] == 0).values.all()
|
| 557 |
+
|
| 558 |
+
# so is this
|
| 559 |
+
cp = df.copy()
|
| 560 |
+
cp.iloc[3:11] = 0
|
| 561 |
+
assert (cp.iloc[3:11] == 0).values.all()
|
| 562 |
+
|
| 563 |
+
result = df.iloc[2:6]
|
| 564 |
+
result2 = df.loc[3:11]
|
| 565 |
+
expected = df.reindex([4, 6, 8, 10])
|
| 566 |
+
|
| 567 |
+
tm.assert_frame_equal(result, expected)
|
| 568 |
+
tm.assert_frame_equal(result2, expected)
|
| 569 |
+
|
| 570 |
+
# non-monotonic, raise KeyError
|
| 571 |
+
df2 = df.iloc[list(range(5)) + list(range(5, 10))[::-1]]
|
| 572 |
+
with pytest.raises(KeyError, match=r"^3$"):
|
| 573 |
+
df2.loc[3:11]
|
| 574 |
+
with pytest.raises(KeyError, match=r"^3$"):
|
| 575 |
+
df2.loc[3:11] = 0
|
| 576 |
+
|
| 577 |
+
@td.skip_array_manager_invalid_test # already covered in test_iloc_col_slice_view
|
| 578 |
+
def test_fancy_getitem_slice_mixed(
|
| 579 |
+
self, float_frame, float_string_frame, using_copy_on_write, warn_copy_on_write
|
| 580 |
+
):
|
| 581 |
+
sliced = float_string_frame.iloc[:, -3:]
|
| 582 |
+
assert sliced["D"].dtype == np.float64
|
| 583 |
+
|
| 584 |
+
# get view with single block
|
| 585 |
+
# setting it triggers setting with copy
|
| 586 |
+
original = float_frame.copy()
|
| 587 |
+
sliced = float_frame.iloc[:, -3:]
|
| 588 |
+
|
| 589 |
+
assert np.shares_memory(sliced["C"]._values, float_frame["C"]._values)
|
| 590 |
+
|
| 591 |
+
with tm.assert_cow_warning(warn_copy_on_write):
|
| 592 |
+
sliced.loc[:, "C"] = 4.0
|
| 593 |
+
if not using_copy_on_write:
|
| 594 |
+
assert (float_frame["C"] == 4).all()
|
| 595 |
+
|
| 596 |
+
# with the enforcement of GH#45333 in 2.0, this remains a view
|
| 597 |
+
np.shares_memory(sliced["C"]._values, float_frame["C"]._values)
|
| 598 |
+
else:
|
| 599 |
+
tm.assert_frame_equal(float_frame, original)
|
| 600 |
+
|
| 601 |
+
def test_getitem_setitem_non_ix_labels(self):
|
| 602 |
+
df = DataFrame(range(20), index=date_range("2020-01-01", periods=20))
|
| 603 |
+
|
| 604 |
+
start, end = df.index[[5, 10]]
|
| 605 |
+
|
| 606 |
+
result = df.loc[start:end]
|
| 607 |
+
result2 = df[start:end]
|
| 608 |
+
expected = df[5:11]
|
| 609 |
+
tm.assert_frame_equal(result, expected)
|
| 610 |
+
tm.assert_frame_equal(result2, expected)
|
| 611 |
+
|
| 612 |
+
result = df.copy()
|
| 613 |
+
result.loc[start:end] = 0
|
| 614 |
+
result2 = df.copy()
|
| 615 |
+
result2[start:end] = 0
|
| 616 |
+
expected = df.copy()
|
| 617 |
+
expected[5:11] = 0
|
| 618 |
+
tm.assert_frame_equal(result, expected)
|
| 619 |
+
tm.assert_frame_equal(result2, expected)
|
| 620 |
+
|
| 621 |
+
def test_ix_multi_take(self):
|
| 622 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((3, 2)))
|
| 623 |
+
rs = df.loc[df.index == 0, :]
|
| 624 |
+
xp = df.reindex([0])
|
| 625 |
+
tm.assert_frame_equal(rs, xp)
|
| 626 |
+
|
| 627 |
+
# GH#1321
|
| 628 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((3, 2)))
|
| 629 |
+
rs = df.loc[df.index == 0, df.columns == 1]
|
| 630 |
+
xp = df.reindex(index=[0], columns=[1])
|
| 631 |
+
tm.assert_frame_equal(rs, xp)
|
| 632 |
+
|
| 633 |
+
def test_getitem_fancy_scalar(self, float_frame):
|
| 634 |
+
f = float_frame
|
| 635 |
+
ix = f.loc
|
| 636 |
+
|
| 637 |
+
# individual value
|
| 638 |
+
for col in f.columns:
|
| 639 |
+
ts = f[col]
|
| 640 |
+
for idx in f.index[::5]:
|
| 641 |
+
assert ix[idx, col] == ts[idx]
|
| 642 |
+
|
| 643 |
+
@td.skip_array_manager_invalid_test # TODO(ArrayManager) rewrite not using .values
|
| 644 |
+
def test_setitem_fancy_scalar(self, float_frame):
|
| 645 |
+
f = float_frame
|
| 646 |
+
expected = float_frame.copy()
|
| 647 |
+
ix = f.loc
|
| 648 |
+
|
| 649 |
+
# individual value
|
| 650 |
+
for j, col in enumerate(f.columns):
|
| 651 |
+
f[col]
|
| 652 |
+
for idx in f.index[::5]:
|
| 653 |
+
i = f.index.get_loc(idx)
|
| 654 |
+
val = np.random.default_rng(2).standard_normal()
|
| 655 |
+
expected.iloc[i, j] = val
|
| 656 |
+
|
| 657 |
+
ix[idx, col] = val
|
| 658 |
+
tm.assert_frame_equal(f, expected)
|
| 659 |
+
|
| 660 |
+
def test_getitem_fancy_boolean(self, float_frame):
|
| 661 |
+
f = float_frame
|
| 662 |
+
ix = f.loc
|
| 663 |
+
|
| 664 |
+
expected = f.reindex(columns=["B", "D"])
|
| 665 |
+
result = ix[:, [False, True, False, True]]
|
| 666 |
+
tm.assert_frame_equal(result, expected)
|
| 667 |
+
|
| 668 |
+
expected = f.reindex(index=f.index[5:10], columns=["B", "D"])
|
| 669 |
+
result = ix[f.index[5:10], [False, True, False, True]]
|
| 670 |
+
tm.assert_frame_equal(result, expected)
|
| 671 |
+
|
| 672 |
+
boolvec = f.index > f.index[7]
|
| 673 |
+
expected = f.reindex(index=f.index[boolvec])
|
| 674 |
+
result = ix[boolvec]
|
| 675 |
+
tm.assert_frame_equal(result, expected)
|
| 676 |
+
result = ix[boolvec, :]
|
| 677 |
+
tm.assert_frame_equal(result, expected)
|
| 678 |
+
|
| 679 |
+
result = ix[boolvec, f.columns[2:]]
|
| 680 |
+
expected = f.reindex(index=f.index[boolvec], columns=["C", "D"])
|
| 681 |
+
tm.assert_frame_equal(result, expected)
|
| 682 |
+
|
| 683 |
+
@td.skip_array_manager_invalid_test # TODO(ArrayManager) rewrite not using .values
|
| 684 |
+
def test_setitem_fancy_boolean(self, float_frame):
|
| 685 |
+
# from 2d, set with booleans
|
| 686 |
+
frame = float_frame.copy()
|
| 687 |
+
expected = float_frame.copy()
|
| 688 |
+
values = expected.values.copy()
|
| 689 |
+
|
| 690 |
+
mask = frame["A"] > 0
|
| 691 |
+
frame.loc[mask] = 0.0
|
| 692 |
+
values[mask.values] = 0.0
|
| 693 |
+
expected = DataFrame(values, index=expected.index, columns=expected.columns)
|
| 694 |
+
tm.assert_frame_equal(frame, expected)
|
| 695 |
+
|
| 696 |
+
frame = float_frame.copy()
|
| 697 |
+
expected = float_frame.copy()
|
| 698 |
+
values = expected.values.copy()
|
| 699 |
+
frame.loc[mask, ["A", "B"]] = 0.0
|
| 700 |
+
values[mask.values, :2] = 0.0
|
| 701 |
+
expected = DataFrame(values, index=expected.index, columns=expected.columns)
|
| 702 |
+
tm.assert_frame_equal(frame, expected)
|
| 703 |
+
|
| 704 |
+
def test_getitem_fancy_ints(self, float_frame):
|
| 705 |
+
result = float_frame.iloc[[1, 4, 7]]
|
| 706 |
+
expected = float_frame.loc[float_frame.index[[1, 4, 7]]]
|
| 707 |
+
tm.assert_frame_equal(result, expected)
|
| 708 |
+
|
| 709 |
+
result = float_frame.iloc[:, [2, 0, 1]]
|
| 710 |
+
expected = float_frame.loc[:, float_frame.columns[[2, 0, 1]]]
|
| 711 |
+
tm.assert_frame_equal(result, expected)
|
| 712 |
+
|
| 713 |
+
def test_getitem_setitem_boolean_misaligned(self, float_frame):
|
| 714 |
+
# boolean index misaligned labels
|
| 715 |
+
mask = float_frame["A"][::-1] > 1
|
| 716 |
+
|
| 717 |
+
result = float_frame.loc[mask]
|
| 718 |
+
expected = float_frame.loc[mask[::-1]]
|
| 719 |
+
tm.assert_frame_equal(result, expected)
|
| 720 |
+
|
| 721 |
+
cp = float_frame.copy()
|
| 722 |
+
expected = float_frame.copy()
|
| 723 |
+
cp.loc[mask] = 0
|
| 724 |
+
expected.loc[mask] = 0
|
| 725 |
+
tm.assert_frame_equal(cp, expected)
|
| 726 |
+
|
| 727 |
+
def test_getitem_setitem_boolean_multi(self):
|
| 728 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((3, 2)))
|
| 729 |
+
|
| 730 |
+
# get
|
| 731 |
+
k1 = np.array([True, False, True])
|
| 732 |
+
k2 = np.array([False, True])
|
| 733 |
+
result = df.loc[k1, k2]
|
| 734 |
+
expected = df.loc[[0, 2], [1]]
|
| 735 |
+
tm.assert_frame_equal(result, expected)
|
| 736 |
+
|
| 737 |
+
expected = df.copy()
|
| 738 |
+
df.loc[np.array([True, False, True]), np.array([False, True])] = 5
|
| 739 |
+
expected.loc[[0, 2], [1]] = 5
|
| 740 |
+
tm.assert_frame_equal(df, expected)
|
| 741 |
+
|
| 742 |
+
def test_getitem_setitem_float_labels(self, using_array_manager):
|
| 743 |
+
index = Index([1.5, 2, 3, 4, 5])
|
| 744 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((5, 5)), index=index)
|
| 745 |
+
|
| 746 |
+
result = df.loc[1.5:4]
|
| 747 |
+
expected = df.reindex([1.5, 2, 3, 4])
|
| 748 |
+
tm.assert_frame_equal(result, expected)
|
| 749 |
+
assert len(result) == 4
|
| 750 |
+
|
| 751 |
+
result = df.loc[4:5]
|
| 752 |
+
expected = df.reindex([4, 5]) # reindex with int
|
| 753 |
+
tm.assert_frame_equal(result, expected, check_index_type=False)
|
| 754 |
+
assert len(result) == 2
|
| 755 |
+
|
| 756 |
+
result = df.loc[4:5]
|
| 757 |
+
expected = df.reindex([4.0, 5.0]) # reindex with float
|
| 758 |
+
tm.assert_frame_equal(result, expected)
|
| 759 |
+
assert len(result) == 2
|
| 760 |
+
|
| 761 |
+
# loc_float changes this to work properly
|
| 762 |
+
result = df.loc[1:2]
|
| 763 |
+
expected = df.iloc[0:2]
|
| 764 |
+
tm.assert_frame_equal(result, expected)
|
| 765 |
+
|
| 766 |
+
expected = df.iloc[0:2]
|
| 767 |
+
msg = r"The behavior of obj\[i:j\] with a float-dtype index"
|
| 768 |
+
with tm.assert_produces_warning(FutureWarning, match=msg):
|
| 769 |
+
result = df[1:2]
|
| 770 |
+
tm.assert_frame_equal(result, expected)
|
| 771 |
+
|
| 772 |
+
# #2727
|
| 773 |
+
index = Index([1.0, 2.5, 3.5, 4.5, 5.0])
|
| 774 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((5, 5)), index=index)
|
| 775 |
+
|
| 776 |
+
# positional slicing only via iloc!
|
| 777 |
+
msg = (
|
| 778 |
+
"cannot do positional indexing on Index with "
|
| 779 |
+
r"these indexers \[1.0\] of type float"
|
| 780 |
+
)
|
| 781 |
+
with pytest.raises(TypeError, match=msg):
|
| 782 |
+
df.iloc[1.0:5]
|
| 783 |
+
|
| 784 |
+
result = df.iloc[4:5]
|
| 785 |
+
expected = df.reindex([5.0])
|
| 786 |
+
tm.assert_frame_equal(result, expected)
|
| 787 |
+
assert len(result) == 1
|
| 788 |
+
|
| 789 |
+
cp = df.copy()
|
| 790 |
+
|
| 791 |
+
with pytest.raises(TypeError, match=_slice_msg):
|
| 792 |
+
cp.iloc[1.0:5] = 0
|
| 793 |
+
|
| 794 |
+
with pytest.raises(TypeError, match=msg):
|
| 795 |
+
result = cp.iloc[1.0:5] == 0
|
| 796 |
+
|
| 797 |
+
assert result.values.all()
|
| 798 |
+
assert (cp.iloc[0:1] == df.iloc[0:1]).values.all()
|
| 799 |
+
|
| 800 |
+
cp = df.copy()
|
| 801 |
+
cp.iloc[4:5] = 0
|
| 802 |
+
assert (cp.iloc[4:5] == 0).values.all()
|
| 803 |
+
assert (cp.iloc[0:4] == df.iloc[0:4]).values.all()
|
| 804 |
+
|
| 805 |
+
# float slicing
|
| 806 |
+
result = df.loc[1.0:5]
|
| 807 |
+
expected = df
|
| 808 |
+
tm.assert_frame_equal(result, expected)
|
| 809 |
+
assert len(result) == 5
|
| 810 |
+
|
| 811 |
+
result = df.loc[1.1:5]
|
| 812 |
+
expected = df.reindex([2.5, 3.5, 4.5, 5.0])
|
| 813 |
+
tm.assert_frame_equal(result, expected)
|
| 814 |
+
assert len(result) == 4
|
| 815 |
+
|
| 816 |
+
result = df.loc[4.51:5]
|
| 817 |
+
expected = df.reindex([5.0])
|
| 818 |
+
tm.assert_frame_equal(result, expected)
|
| 819 |
+
assert len(result) == 1
|
| 820 |
+
|
| 821 |
+
result = df.loc[1.0:5.0]
|
| 822 |
+
expected = df.reindex([1.0, 2.5, 3.5, 4.5, 5.0])
|
| 823 |
+
tm.assert_frame_equal(result, expected)
|
| 824 |
+
assert len(result) == 5
|
| 825 |
+
|
| 826 |
+
cp = df.copy()
|
| 827 |
+
cp.loc[1.0:5.0] = 0
|
| 828 |
+
result = cp.loc[1.0:5.0]
|
| 829 |
+
assert (result == 0).values.all()
|
| 830 |
+
|
| 831 |
+
def test_setitem_single_column_mixed_datetime(self):
|
| 832 |
+
df = DataFrame(
|
| 833 |
+
np.random.default_rng(2).standard_normal((5, 3)),
|
| 834 |
+
index=["a", "b", "c", "d", "e"],
|
| 835 |
+
columns=["foo", "bar", "baz"],
|
| 836 |
+
)
|
| 837 |
+
|
| 838 |
+
df["timestamp"] = Timestamp("20010102")
|
| 839 |
+
|
| 840 |
+
# check our dtypes
|
| 841 |
+
result = df.dtypes
|
| 842 |
+
expected = Series(
|
| 843 |
+
[np.dtype("float64")] * 3 + [np.dtype("datetime64[s]")],
|
| 844 |
+
index=["foo", "bar", "baz", "timestamp"],
|
| 845 |
+
)
|
| 846 |
+
tm.assert_series_equal(result, expected)
|
| 847 |
+
|
| 848 |
+
# GH#16674 iNaT is treated as an integer when given by the user
|
| 849 |
+
with tm.assert_produces_warning(
|
| 850 |
+
FutureWarning, match="Setting an item of incompatible dtype"
|
| 851 |
+
):
|
| 852 |
+
df.loc["b", "timestamp"] = iNaT
|
| 853 |
+
assert not isna(df.loc["b", "timestamp"])
|
| 854 |
+
assert df["timestamp"].dtype == np.object_
|
| 855 |
+
assert df.loc["b", "timestamp"] == iNaT
|
| 856 |
+
|
| 857 |
+
# allow this syntax (as of GH#3216)
|
| 858 |
+
df.loc["c", "timestamp"] = np.nan
|
| 859 |
+
assert isna(df.loc["c", "timestamp"])
|
| 860 |
+
|
| 861 |
+
# allow this syntax
|
| 862 |
+
df.loc["d", :] = np.nan
|
| 863 |
+
assert not isna(df.loc["c", :]).all()
|
| 864 |
+
|
| 865 |
+
def test_setitem_mixed_datetime(self):
|
| 866 |
+
# GH 9336
|
| 867 |
+
expected = DataFrame(
|
| 868 |
+
{
|
| 869 |
+
"a": [0, 0, 0, 0, 13, 14],
|
| 870 |
+
"b": [
|
| 871 |
+
datetime(2012, 1, 1),
|
| 872 |
+
1,
|
| 873 |
+
"x",
|
| 874 |
+
"y",
|
| 875 |
+
datetime(2013, 1, 1),
|
| 876 |
+
datetime(2014, 1, 1),
|
| 877 |
+
],
|
| 878 |
+
}
|
| 879 |
+
)
|
| 880 |
+
df = DataFrame(0, columns=list("ab"), index=range(6))
|
| 881 |
+
df["b"] = pd.NaT
|
| 882 |
+
df.loc[0, "b"] = datetime(2012, 1, 1)
|
| 883 |
+
with tm.assert_produces_warning(
|
| 884 |
+
FutureWarning, match="Setting an item of incompatible dtype"
|
| 885 |
+
):
|
| 886 |
+
df.loc[1, "b"] = 1
|
| 887 |
+
df.loc[[2, 3], "b"] = "x", "y"
|
| 888 |
+
A = np.array(
|
| 889 |
+
[
|
| 890 |
+
[13, np.datetime64("2013-01-01T00:00:00")],
|
| 891 |
+
[14, np.datetime64("2014-01-01T00:00:00")],
|
| 892 |
+
]
|
| 893 |
+
)
|
| 894 |
+
df.loc[[4, 5], ["a", "b"]] = A
|
| 895 |
+
tm.assert_frame_equal(df, expected)
|
| 896 |
+
|
| 897 |
+
def test_setitem_frame_float(self, float_frame):
|
| 898 |
+
piece = float_frame.loc[float_frame.index[:2], ["A", "B"]]
|
| 899 |
+
float_frame.loc[float_frame.index[-2] :, ["A", "B"]] = piece.values
|
| 900 |
+
result = float_frame.loc[float_frame.index[-2:], ["A", "B"]].values
|
| 901 |
+
expected = piece.values
|
| 902 |
+
tm.assert_almost_equal(result, expected)
|
| 903 |
+
|
| 904 |
+
def test_setitem_frame_mixed(self, float_string_frame):
|
| 905 |
+
# GH 3216
|
| 906 |
+
|
| 907 |
+
# already aligned
|
| 908 |
+
f = float_string_frame.copy()
|
| 909 |
+
piece = DataFrame(
|
| 910 |
+
[[1.0, 2.0], [3.0, 4.0]], index=f.index[0:2], columns=["A", "B"]
|
| 911 |
+
)
|
| 912 |
+
key = (f.index[slice(None, 2)], ["A", "B"])
|
| 913 |
+
f.loc[key] = piece
|
| 914 |
+
tm.assert_almost_equal(f.loc[f.index[0:2], ["A", "B"]].values, piece.values)
|
| 915 |
+
|
| 916 |
+
def test_setitem_frame_mixed_rows_unaligned(self, float_string_frame):
|
| 917 |
+
# GH#3216 rows unaligned
|
| 918 |
+
f = float_string_frame.copy()
|
| 919 |
+
piece = DataFrame(
|
| 920 |
+
[[1.0, 2.0], [3.0, 4.0], [5.0, 6.0], [7.0, 8.0]],
|
| 921 |
+
index=list(f.index[0:2]) + ["foo", "bar"],
|
| 922 |
+
columns=["A", "B"],
|
| 923 |
+
)
|
| 924 |
+
key = (f.index[slice(None, 2)], ["A", "B"])
|
| 925 |
+
f.loc[key] = piece
|
| 926 |
+
tm.assert_almost_equal(
|
| 927 |
+
f.loc[f.index[0:2:], ["A", "B"]].values, piece.values[0:2]
|
| 928 |
+
)
|
| 929 |
+
|
| 930 |
+
def test_setitem_frame_mixed_key_unaligned(self, float_string_frame):
|
| 931 |
+
# GH#3216 key is unaligned with values
|
| 932 |
+
f = float_string_frame.copy()
|
| 933 |
+
piece = f.loc[f.index[:2], ["A"]]
|
| 934 |
+
piece.index = f.index[-2:]
|
| 935 |
+
key = (f.index[slice(-2, None)], ["A", "B"])
|
| 936 |
+
f.loc[key] = piece
|
| 937 |
+
piece["B"] = np.nan
|
| 938 |
+
tm.assert_almost_equal(f.loc[f.index[-2:], ["A", "B"]].values, piece.values)
|
| 939 |
+
|
| 940 |
+
def test_setitem_frame_mixed_ndarray(self, float_string_frame):
|
| 941 |
+
# GH#3216 ndarray
|
| 942 |
+
f = float_string_frame.copy()
|
| 943 |
+
piece = float_string_frame.loc[f.index[:2], ["A", "B"]]
|
| 944 |
+
key = (f.index[slice(-2, None)], ["A", "B"])
|
| 945 |
+
f.loc[key] = piece.values
|
| 946 |
+
tm.assert_almost_equal(f.loc[f.index[-2:], ["A", "B"]].values, piece.values)
|
| 947 |
+
|
| 948 |
+
def test_setitem_frame_upcast(self):
|
| 949 |
+
# needs upcasting
|
| 950 |
+
df = DataFrame([[1, 2, "foo"], [3, 4, "bar"]], columns=["A", "B", "C"])
|
| 951 |
+
df2 = df.copy()
|
| 952 |
+
with tm.assert_produces_warning(FutureWarning, match="incompatible dtype"):
|
| 953 |
+
df2.loc[:, ["A", "B"]] = df.loc[:, ["A", "B"]] + 0.5
|
| 954 |
+
expected = df.reindex(columns=["A", "B"])
|
| 955 |
+
expected += 0.5
|
| 956 |
+
expected["C"] = df["C"]
|
| 957 |
+
tm.assert_frame_equal(df2, expected)
|
| 958 |
+
|
| 959 |
+
def test_setitem_frame_align(self, float_frame):
|
| 960 |
+
piece = float_frame.loc[float_frame.index[:2], ["A", "B"]]
|
| 961 |
+
piece.index = float_frame.index[-2:]
|
| 962 |
+
piece.columns = ["A", "B"]
|
| 963 |
+
float_frame.loc[float_frame.index[-2:], ["A", "B"]] = piece
|
| 964 |
+
result = float_frame.loc[float_frame.index[-2:], ["A", "B"]].values
|
| 965 |
+
expected = piece.values
|
| 966 |
+
tm.assert_almost_equal(result, expected)
|
| 967 |
+
|
| 968 |
+
def test_getitem_setitem_ix_duplicates(self):
|
| 969 |
+
# #1201
|
| 970 |
+
df = DataFrame(
|
| 971 |
+
np.random.default_rng(2).standard_normal((5, 3)),
|
| 972 |
+
index=["foo", "foo", "bar", "baz", "bar"],
|
| 973 |
+
)
|
| 974 |
+
|
| 975 |
+
result = df.loc["foo"]
|
| 976 |
+
expected = df[:2]
|
| 977 |
+
tm.assert_frame_equal(result, expected)
|
| 978 |
+
|
| 979 |
+
result = df.loc["bar"]
|
| 980 |
+
expected = df.iloc[[2, 4]]
|
| 981 |
+
tm.assert_frame_equal(result, expected)
|
| 982 |
+
|
| 983 |
+
result = df.loc["baz"]
|
| 984 |
+
expected = df.iloc[3]
|
| 985 |
+
tm.assert_series_equal(result, expected)
|
| 986 |
+
|
| 987 |
+
def test_getitem_ix_boolean_duplicates_multiple(self):
|
| 988 |
+
# #1201
|
| 989 |
+
df = DataFrame(
|
| 990 |
+
np.random.default_rng(2).standard_normal((5, 3)),
|
| 991 |
+
index=["foo", "foo", "bar", "baz", "bar"],
|
| 992 |
+
)
|
| 993 |
+
|
| 994 |
+
result = df.loc[["bar"]]
|
| 995 |
+
exp = df.iloc[[2, 4]]
|
| 996 |
+
tm.assert_frame_equal(result, exp)
|
| 997 |
+
|
| 998 |
+
result = df.loc[df[1] > 0]
|
| 999 |
+
exp = df[df[1] > 0]
|
| 1000 |
+
tm.assert_frame_equal(result, exp)
|
| 1001 |
+
|
| 1002 |
+
result = df.loc[df[0] > 0]
|
| 1003 |
+
exp = df[df[0] > 0]
|
| 1004 |
+
tm.assert_frame_equal(result, exp)
|
| 1005 |
+
|
| 1006 |
+
@pytest.mark.parametrize("bool_value", [True, False])
|
| 1007 |
+
def test_getitem_setitem_ix_bool_keyerror(self, bool_value):
|
| 1008 |
+
# #2199
|
| 1009 |
+
df = DataFrame({"a": [1, 2, 3]})
|
| 1010 |
+
message = f"{bool_value}: boolean label can not be used without a boolean index"
|
| 1011 |
+
with pytest.raises(KeyError, match=message):
|
| 1012 |
+
df.loc[bool_value]
|
| 1013 |
+
|
| 1014 |
+
msg = "cannot use a single bool to index into setitem"
|
| 1015 |
+
with pytest.raises(KeyError, match=msg):
|
| 1016 |
+
df.loc[bool_value] = 0
|
| 1017 |
+
|
| 1018 |
+
# TODO: rename? remove?
|
| 1019 |
+
def test_single_element_ix_dont_upcast(self, float_frame):
|
| 1020 |
+
float_frame["E"] = 1
|
| 1021 |
+
assert issubclass(float_frame["E"].dtype.type, (int, np.integer))
|
| 1022 |
+
|
| 1023 |
+
result = float_frame.loc[float_frame.index[5], "E"]
|
| 1024 |
+
assert is_integer(result)
|
| 1025 |
+
|
| 1026 |
+
# GH 11617
|
| 1027 |
+
df = DataFrame({"a": [1.23]})
|
| 1028 |
+
df["b"] = 666
|
| 1029 |
+
|
| 1030 |
+
result = df.loc[0, "b"]
|
| 1031 |
+
assert is_integer(result)
|
| 1032 |
+
|
| 1033 |
+
expected = Series([666], [0], name="b")
|
| 1034 |
+
result = df.loc[[0], "b"]
|
| 1035 |
+
tm.assert_series_equal(result, expected)
|
| 1036 |
+
|
| 1037 |
+
def test_iloc_callable_tuple_return_value(self):
|
| 1038 |
+
# GH53769
|
| 1039 |
+
df = DataFrame(np.arange(40).reshape(10, 4), index=range(0, 20, 2))
|
| 1040 |
+
msg = "callable with iloc"
|
| 1041 |
+
with tm.assert_produces_warning(FutureWarning, match=msg):
|
| 1042 |
+
df.iloc[lambda _: (0,)]
|
| 1043 |
+
with tm.assert_produces_warning(FutureWarning, match=msg):
|
| 1044 |
+
df.iloc[lambda _: (0,)] = 1
|
| 1045 |
+
|
| 1046 |
+
def test_iloc_row(self):
|
| 1047 |
+
df = DataFrame(
|
| 1048 |
+
np.random.default_rng(2).standard_normal((10, 4)), index=range(0, 20, 2)
|
| 1049 |
+
)
|
| 1050 |
+
|
| 1051 |
+
result = df.iloc[1]
|
| 1052 |
+
exp = df.loc[2]
|
| 1053 |
+
tm.assert_series_equal(result, exp)
|
| 1054 |
+
|
| 1055 |
+
result = df.iloc[2]
|
| 1056 |
+
exp = df.loc[4]
|
| 1057 |
+
tm.assert_series_equal(result, exp)
|
| 1058 |
+
|
| 1059 |
+
# slice
|
| 1060 |
+
result = df.iloc[slice(4, 8)]
|
| 1061 |
+
expected = df.loc[8:14]
|
| 1062 |
+
tm.assert_frame_equal(result, expected)
|
| 1063 |
+
|
| 1064 |
+
# list of integers
|
| 1065 |
+
result = df.iloc[[1, 2, 4, 6]]
|
| 1066 |
+
expected = df.reindex(df.index[[1, 2, 4, 6]])
|
| 1067 |
+
tm.assert_frame_equal(result, expected)
|
| 1068 |
+
|
| 1069 |
+
def test_iloc_row_slice_view(self, using_copy_on_write, warn_copy_on_write):
|
| 1070 |
+
df = DataFrame(
|
| 1071 |
+
np.random.default_rng(2).standard_normal((10, 4)), index=range(0, 20, 2)
|
| 1072 |
+
)
|
| 1073 |
+
original = df.copy()
|
| 1074 |
+
|
| 1075 |
+
# verify slice is view
|
| 1076 |
+
# setting it makes it raise/warn
|
| 1077 |
+
subset = df.iloc[slice(4, 8)]
|
| 1078 |
+
|
| 1079 |
+
assert np.shares_memory(df[2], subset[2])
|
| 1080 |
+
|
| 1081 |
+
exp_col = original[2].copy()
|
| 1082 |
+
with tm.assert_cow_warning(warn_copy_on_write):
|
| 1083 |
+
subset.loc[:, 2] = 0.0
|
| 1084 |
+
if not using_copy_on_write:
|
| 1085 |
+
exp_col._values[4:8] = 0.0
|
| 1086 |
+
|
| 1087 |
+
# With the enforcement of GH#45333 in 2.0, this remains a view
|
| 1088 |
+
assert np.shares_memory(df[2], subset[2])
|
| 1089 |
+
tm.assert_series_equal(df[2], exp_col)
|
| 1090 |
+
|
| 1091 |
+
def test_iloc_col(self):
|
| 1092 |
+
df = DataFrame(
|
| 1093 |
+
np.random.default_rng(2).standard_normal((4, 10)), columns=range(0, 20, 2)
|
| 1094 |
+
)
|
| 1095 |
+
|
| 1096 |
+
result = df.iloc[:, 1]
|
| 1097 |
+
exp = df.loc[:, 2]
|
| 1098 |
+
tm.assert_series_equal(result, exp)
|
| 1099 |
+
|
| 1100 |
+
result = df.iloc[:, 2]
|
| 1101 |
+
exp = df.loc[:, 4]
|
| 1102 |
+
tm.assert_series_equal(result, exp)
|
| 1103 |
+
|
| 1104 |
+
# slice
|
| 1105 |
+
result = df.iloc[:, slice(4, 8)]
|
| 1106 |
+
expected = df.loc[:, 8:14]
|
| 1107 |
+
tm.assert_frame_equal(result, expected)
|
| 1108 |
+
|
| 1109 |
+
# list of integers
|
| 1110 |
+
result = df.iloc[:, [1, 2, 4, 6]]
|
| 1111 |
+
expected = df.reindex(columns=df.columns[[1, 2, 4, 6]])
|
| 1112 |
+
tm.assert_frame_equal(result, expected)
|
| 1113 |
+
|
| 1114 |
+
def test_iloc_col_slice_view(
|
| 1115 |
+
self, using_array_manager, using_copy_on_write, warn_copy_on_write
|
| 1116 |
+
):
|
| 1117 |
+
df = DataFrame(
|
| 1118 |
+
np.random.default_rng(2).standard_normal((4, 10)), columns=range(0, 20, 2)
|
| 1119 |
+
)
|
| 1120 |
+
original = df.copy()
|
| 1121 |
+
subset = df.iloc[:, slice(4, 8)]
|
| 1122 |
+
|
| 1123 |
+
if not using_array_manager and not using_copy_on_write:
|
| 1124 |
+
# verify slice is view
|
| 1125 |
+
assert np.shares_memory(df[8]._values, subset[8]._values)
|
| 1126 |
+
|
| 1127 |
+
with tm.assert_cow_warning(warn_copy_on_write):
|
| 1128 |
+
subset.loc[:, 8] = 0.0
|
| 1129 |
+
|
| 1130 |
+
assert (df[8] == 0).all()
|
| 1131 |
+
|
| 1132 |
+
# with the enforcement of GH#45333 in 2.0, this remains a view
|
| 1133 |
+
assert np.shares_memory(df[8]._values, subset[8]._values)
|
| 1134 |
+
else:
|
| 1135 |
+
if using_copy_on_write:
|
| 1136 |
+
# verify slice is view
|
| 1137 |
+
assert np.shares_memory(df[8]._values, subset[8]._values)
|
| 1138 |
+
subset[8] = 0.0
|
| 1139 |
+
# subset changed
|
| 1140 |
+
assert (subset[8] == 0).all()
|
| 1141 |
+
# but df itself did not change (setitem replaces full column)
|
| 1142 |
+
tm.assert_frame_equal(df, original)
|
| 1143 |
+
|
| 1144 |
+
def test_loc_duplicates(self):
|
| 1145 |
+
# gh-17105
|
| 1146 |
+
|
| 1147 |
+
# insert a duplicate element to the index
|
| 1148 |
+
trange = date_range(
|
| 1149 |
+
start=Timestamp(year=2017, month=1, day=1),
|
| 1150 |
+
end=Timestamp(year=2017, month=1, day=5),
|
| 1151 |
+
)
|
| 1152 |
+
|
| 1153 |
+
trange = trange.insert(loc=5, item=Timestamp(year=2017, month=1, day=5))
|
| 1154 |
+
|
| 1155 |
+
df = DataFrame(0, index=trange, columns=["A", "B"])
|
| 1156 |
+
bool_idx = np.array([False, False, False, False, False, True])
|
| 1157 |
+
|
| 1158 |
+
# assignment
|
| 1159 |
+
df.loc[trange[bool_idx], "A"] = 6
|
| 1160 |
+
|
| 1161 |
+
expected = DataFrame(
|
| 1162 |
+
{"A": [0, 0, 0, 0, 6, 6], "B": [0, 0, 0, 0, 0, 0]}, index=trange
|
| 1163 |
+
)
|
| 1164 |
+
tm.assert_frame_equal(df, expected)
|
| 1165 |
+
|
| 1166 |
+
# in-place
|
| 1167 |
+
df = DataFrame(0, index=trange, columns=["A", "B"])
|
| 1168 |
+
df.loc[trange[bool_idx], "A"] += 6
|
| 1169 |
+
tm.assert_frame_equal(df, expected)
|
| 1170 |
+
|
| 1171 |
+
def test_setitem_with_unaligned_tz_aware_datetime_column(self):
|
| 1172 |
+
# GH 12981
|
| 1173 |
+
# Assignment of unaligned offset-aware datetime series.
|
| 1174 |
+
# Make sure timezone isn't lost
|
| 1175 |
+
column = Series(date_range("2015-01-01", periods=3, tz="utc"), name="dates")
|
| 1176 |
+
df = DataFrame({"dates": column})
|
| 1177 |
+
df["dates"] = column[[1, 0, 2]]
|
| 1178 |
+
tm.assert_series_equal(df["dates"], column)
|
| 1179 |
+
|
| 1180 |
+
df = DataFrame({"dates": column})
|
| 1181 |
+
df.loc[[0, 1, 2], "dates"] = column[[1, 0, 2]]
|
| 1182 |
+
tm.assert_series_equal(df["dates"], column)
|
| 1183 |
+
|
| 1184 |
+
def test_loc_setitem_datetimelike_with_inference(self):
|
| 1185 |
+
# GH 7592
|
| 1186 |
+
# assignment of timedeltas with NaT
|
| 1187 |
+
|
| 1188 |
+
one_hour = timedelta(hours=1)
|
| 1189 |
+
df = DataFrame(index=date_range("20130101", periods=4))
|
| 1190 |
+
df["A"] = np.array([1 * one_hour] * 4, dtype="m8[ns]")
|
| 1191 |
+
df.loc[:, "B"] = np.array([2 * one_hour] * 4, dtype="m8[ns]")
|
| 1192 |
+
df.loc[df.index[:3], "C"] = np.array([3 * one_hour] * 3, dtype="m8[ns]")
|
| 1193 |
+
df.loc[:, "D"] = np.array([4 * one_hour] * 4, dtype="m8[ns]")
|
| 1194 |
+
df.loc[df.index[:3], "E"] = np.array([5 * one_hour] * 3, dtype="m8[ns]")
|
| 1195 |
+
df["F"] = np.timedelta64("NaT")
|
| 1196 |
+
df.loc[df.index[:-1], "F"] = np.array([6 * one_hour] * 3, dtype="m8[ns]")
|
| 1197 |
+
df.loc[df.index[-3] :, "G"] = date_range("20130101", periods=3)
|
| 1198 |
+
df["H"] = np.datetime64("NaT")
|
| 1199 |
+
result = df.dtypes
|
| 1200 |
+
expected = Series(
|
| 1201 |
+
[np.dtype("timedelta64[ns]")] * 6 + [np.dtype("datetime64[ns]")] * 2,
|
| 1202 |
+
index=list("ABCDEFGH"),
|
| 1203 |
+
)
|
| 1204 |
+
tm.assert_series_equal(result, expected)
|
| 1205 |
+
|
| 1206 |
+
def test_getitem_boolean_indexing_mixed(self):
|
| 1207 |
+
df = DataFrame(
|
| 1208 |
+
{
|
| 1209 |
+
0: {35: np.nan, 40: np.nan, 43: np.nan, 49: np.nan, 50: np.nan},
|
| 1210 |
+
1: {
|
| 1211 |
+
35: np.nan,
|
| 1212 |
+
40: 0.32632316859446198,
|
| 1213 |
+
43: np.nan,
|
| 1214 |
+
49: 0.32632316859446198,
|
| 1215 |
+
50: 0.39114724480578139,
|
| 1216 |
+
},
|
| 1217 |
+
2: {
|
| 1218 |
+
35: np.nan,
|
| 1219 |
+
40: np.nan,
|
| 1220 |
+
43: 0.29012581014105987,
|
| 1221 |
+
49: np.nan,
|
| 1222 |
+
50: np.nan,
|
| 1223 |
+
},
|
| 1224 |
+
3: {35: np.nan, 40: np.nan, 43: np.nan, 49: np.nan, 50: np.nan},
|
| 1225 |
+
4: {
|
| 1226 |
+
35: 0.34215328467153283,
|
| 1227 |
+
40: np.nan,
|
| 1228 |
+
43: np.nan,
|
| 1229 |
+
49: np.nan,
|
| 1230 |
+
50: np.nan,
|
| 1231 |
+
},
|
| 1232 |
+
"y": {35: 0, 40: 0, 43: 0, 49: 0, 50: 1},
|
| 1233 |
+
}
|
| 1234 |
+
)
|
| 1235 |
+
|
| 1236 |
+
# mixed int/float ok
|
| 1237 |
+
df2 = df.copy()
|
| 1238 |
+
df2[df2 > 0.3] = 1
|
| 1239 |
+
expected = df.copy()
|
| 1240 |
+
expected.loc[40, 1] = 1
|
| 1241 |
+
expected.loc[49, 1] = 1
|
| 1242 |
+
expected.loc[50, 1] = 1
|
| 1243 |
+
expected.loc[35, 4] = 1
|
| 1244 |
+
tm.assert_frame_equal(df2, expected)
|
| 1245 |
+
|
| 1246 |
+
df["foo"] = "test"
|
| 1247 |
+
msg = "not supported between instances|unorderable types"
|
| 1248 |
+
|
| 1249 |
+
with pytest.raises(TypeError, match=msg):
|
| 1250 |
+
df[df > 0.3] = 1
|
| 1251 |
+
|
| 1252 |
+
def test_type_error_multiindex(self):
|
| 1253 |
+
# See gh-12218
|
| 1254 |
+
mi = MultiIndex.from_product([["x", "y"], [0, 1]], names=[None, "c"])
|
| 1255 |
+
dg = DataFrame(
|
| 1256 |
+
[[1, 1, 2, 2], [3, 3, 4, 4]], columns=mi, index=Index([0, 1], name="i")
|
| 1257 |
+
)
|
| 1258 |
+
with pytest.raises(InvalidIndexError, match="slice"):
|
| 1259 |
+
dg[:, 0]
|
| 1260 |
+
|
| 1261 |
+
index = Index(range(2), name="i")
|
| 1262 |
+
columns = MultiIndex(
|
| 1263 |
+
levels=[["x", "y"], [0, 1]], codes=[[0, 1], [0, 0]], names=[None, "c"]
|
| 1264 |
+
)
|
| 1265 |
+
expected = DataFrame([[1, 2], [3, 4]], columns=columns, index=index)
|
| 1266 |
+
|
| 1267 |
+
result = dg.loc[:, (slice(None), 0)]
|
| 1268 |
+
tm.assert_frame_equal(result, expected)
|
| 1269 |
+
|
| 1270 |
+
name = ("x", 0)
|
| 1271 |
+
index = Index(range(2), name="i")
|
| 1272 |
+
expected = Series([1, 3], index=index, name=name)
|
| 1273 |
+
|
| 1274 |
+
result = dg["x", 0]
|
| 1275 |
+
tm.assert_series_equal(result, expected)
|
| 1276 |
+
|
| 1277 |
+
def test_getitem_interval_index_partial_indexing(self):
|
| 1278 |
+
# GH#36490
|
| 1279 |
+
df = DataFrame(
|
| 1280 |
+
np.ones((3, 4)), columns=pd.IntervalIndex.from_breaks(np.arange(5))
|
| 1281 |
+
)
|
| 1282 |
+
|
| 1283 |
+
expected = df.iloc[:, 0]
|
| 1284 |
+
|
| 1285 |
+
res = df[0.5]
|
| 1286 |
+
tm.assert_series_equal(res, expected)
|
| 1287 |
+
|
| 1288 |
+
res = df.loc[:, 0.5]
|
| 1289 |
+
tm.assert_series_equal(res, expected)
|
| 1290 |
+
|
| 1291 |
+
def test_setitem_array_as_cell_value(self):
|
| 1292 |
+
# GH#43422
|
| 1293 |
+
df = DataFrame(columns=["a", "b"], dtype=object)
|
| 1294 |
+
df.loc[0] = {"a": np.zeros((2,)), "b": np.zeros((2, 2))}
|
| 1295 |
+
expected = DataFrame({"a": [np.zeros((2,))], "b": [np.zeros((2, 2))]})
|
| 1296 |
+
tm.assert_frame_equal(df, expected)
|
| 1297 |
+
|
| 1298 |
+
def test_iloc_setitem_nullable_2d_values(self):
|
| 1299 |
+
df = DataFrame({"A": [1, 2, 3]}, dtype="Int64")
|
| 1300 |
+
orig = df.copy()
|
| 1301 |
+
|
| 1302 |
+
df.loc[:] = df.values[:, ::-1]
|
| 1303 |
+
tm.assert_frame_equal(df, orig)
|
| 1304 |
+
|
| 1305 |
+
df.loc[:] = pd.core.arrays.NumpyExtensionArray(df.values[:, ::-1])
|
| 1306 |
+
tm.assert_frame_equal(df, orig)
|
| 1307 |
+
|
| 1308 |
+
df.iloc[:] = df.iloc[:, :].copy()
|
| 1309 |
+
tm.assert_frame_equal(df, orig)
|
| 1310 |
+
|
| 1311 |
+
def test_getitem_segfault_with_empty_like_object(self):
|
| 1312 |
+
# GH#46848
|
| 1313 |
+
df = DataFrame(np.empty((1, 1), dtype=object))
|
| 1314 |
+
df[0] = np.empty_like(df[0])
|
| 1315 |
+
# this produces the segfault
|
| 1316 |
+
df[[0]]
|
| 1317 |
+
|
| 1318 |
+
@pytest.mark.filterwarnings("ignore:Setting a value on a view:FutureWarning")
|
| 1319 |
+
@pytest.mark.parametrize(
|
| 1320 |
+
"null", [pd.NaT, pd.NaT.to_numpy("M8[ns]"), pd.NaT.to_numpy("m8[ns]")]
|
| 1321 |
+
)
|
| 1322 |
+
def test_setting_mismatched_na_into_nullable_fails(
|
| 1323 |
+
self, null, any_numeric_ea_dtype
|
| 1324 |
+
):
|
| 1325 |
+
# GH#44514 don't cast mismatched nulls to pd.NA
|
| 1326 |
+
df = DataFrame({"A": [1, 2, 3]}, dtype=any_numeric_ea_dtype)
|
| 1327 |
+
ser = df["A"].copy()
|
| 1328 |
+
arr = ser._values
|
| 1329 |
+
|
| 1330 |
+
msg = "|".join(
|
| 1331 |
+
[
|
| 1332 |
+
r"timedelta64\[ns\] cannot be converted to (Floating|Integer)Dtype",
|
| 1333 |
+
r"datetime64\[ns\] cannot be converted to (Floating|Integer)Dtype",
|
| 1334 |
+
"'values' contains non-numeric NA",
|
| 1335 |
+
r"Invalid value '.*' for dtype (U?Int|Float)\d{1,2}",
|
| 1336 |
+
]
|
| 1337 |
+
)
|
| 1338 |
+
with pytest.raises(TypeError, match=msg):
|
| 1339 |
+
arr[0] = null
|
| 1340 |
+
|
| 1341 |
+
with pytest.raises(TypeError, match=msg):
|
| 1342 |
+
arr[:2] = [null, null]
|
| 1343 |
+
|
| 1344 |
+
with pytest.raises(TypeError, match=msg):
|
| 1345 |
+
ser[0] = null
|
| 1346 |
+
|
| 1347 |
+
with pytest.raises(TypeError, match=msg):
|
| 1348 |
+
ser[:2] = [null, null]
|
| 1349 |
+
|
| 1350 |
+
with pytest.raises(TypeError, match=msg):
|
| 1351 |
+
ser.iloc[0] = null
|
| 1352 |
+
|
| 1353 |
+
with pytest.raises(TypeError, match=msg):
|
| 1354 |
+
ser.iloc[:2] = [null, null]
|
| 1355 |
+
|
| 1356 |
+
with pytest.raises(TypeError, match=msg):
|
| 1357 |
+
df.iloc[0, 0] = null
|
| 1358 |
+
|
| 1359 |
+
with pytest.raises(TypeError, match=msg):
|
| 1360 |
+
df.iloc[:2, 0] = [null, null]
|
| 1361 |
+
|
| 1362 |
+
# Multi-Block
|
| 1363 |
+
df2 = df.copy()
|
| 1364 |
+
df2["B"] = ser.copy()
|
| 1365 |
+
with pytest.raises(TypeError, match=msg):
|
| 1366 |
+
df2.iloc[0, 0] = null
|
| 1367 |
+
|
| 1368 |
+
with pytest.raises(TypeError, match=msg):
|
| 1369 |
+
df2.iloc[:2, 0] = [null, null]
|
| 1370 |
+
|
| 1371 |
+
def test_loc_expand_empty_frame_keep_index_name(self):
|
| 1372 |
+
# GH#45621
|
| 1373 |
+
df = DataFrame(columns=["b"], index=Index([], name="a"))
|
| 1374 |
+
df.loc[0] = 1
|
| 1375 |
+
expected = DataFrame({"b": [1]}, index=Index([0], name="a"))
|
| 1376 |
+
tm.assert_frame_equal(df, expected)
|
| 1377 |
+
|
| 1378 |
+
def test_loc_expand_empty_frame_keep_midx_names(self):
|
| 1379 |
+
# GH#46317
|
| 1380 |
+
df = DataFrame(
|
| 1381 |
+
columns=["d"], index=MultiIndex.from_tuples([], names=["a", "b", "c"])
|
| 1382 |
+
)
|
| 1383 |
+
df.loc[(1, 2, 3)] = "foo"
|
| 1384 |
+
expected = DataFrame(
|
| 1385 |
+
{"d": ["foo"]},
|
| 1386 |
+
index=MultiIndex.from_tuples([(1, 2, 3)], names=["a", "b", "c"]),
|
| 1387 |
+
)
|
| 1388 |
+
tm.assert_frame_equal(df, expected)
|
| 1389 |
+
|
| 1390 |
+
@pytest.mark.parametrize(
|
| 1391 |
+
"val, idxr",
|
| 1392 |
+
[
|
| 1393 |
+
("x", "a"),
|
| 1394 |
+
("x", ["a"]),
|
| 1395 |
+
(1, "a"),
|
| 1396 |
+
(1, ["a"]),
|
| 1397 |
+
],
|
| 1398 |
+
)
|
| 1399 |
+
def test_loc_setitem_rhs_frame(self, idxr, val):
|
| 1400 |
+
# GH#47578
|
| 1401 |
+
df = DataFrame({"a": [1, 2]})
|
| 1402 |
+
|
| 1403 |
+
with tm.assert_produces_warning(
|
| 1404 |
+
FutureWarning, match="Setting an item of incompatible dtype"
|
| 1405 |
+
):
|
| 1406 |
+
df.loc[:, idxr] = DataFrame({"a": [val, 11]}, index=[1, 2])
|
| 1407 |
+
expected = DataFrame({"a": [np.nan, val]})
|
| 1408 |
+
tm.assert_frame_equal(df, expected)
|
| 1409 |
+
|
| 1410 |
+
@td.skip_array_manager_invalid_test
|
| 1411 |
+
def test_iloc_setitem_enlarge_no_warning(self, warn_copy_on_write):
|
| 1412 |
+
# GH#47381
|
| 1413 |
+
df = DataFrame(columns=["a", "b"])
|
| 1414 |
+
expected = df.copy()
|
| 1415 |
+
view = df[:]
|
| 1416 |
+
df.iloc[:, 0] = np.array([1, 2], dtype=np.float64)
|
| 1417 |
+
tm.assert_frame_equal(view, expected)
|
| 1418 |
+
|
| 1419 |
+
def test_loc_internals_not_updated_correctly(self):
|
| 1420 |
+
# GH#47867 all steps are necessary to reproduce the initial bug
|
| 1421 |
+
df = DataFrame(
|
| 1422 |
+
{"bool_col": True, "a": 1, "b": 2.5},
|
| 1423 |
+
index=MultiIndex.from_arrays([[1, 2], [1, 2]], names=["idx1", "idx2"]),
|
| 1424 |
+
)
|
| 1425 |
+
idx = [(1, 1)]
|
| 1426 |
+
|
| 1427 |
+
df["c"] = 3
|
| 1428 |
+
df.loc[idx, "c"] = 0
|
| 1429 |
+
|
| 1430 |
+
df.loc[idx, "c"]
|
| 1431 |
+
df.loc[idx, ["a", "b"]]
|
| 1432 |
+
|
| 1433 |
+
df.loc[idx, "c"] = 15
|
| 1434 |
+
result = df.loc[idx, "c"]
|
| 1435 |
+
expected = df = Series(
|
| 1436 |
+
15,
|
| 1437 |
+
index=MultiIndex.from_arrays([[1], [1]], names=["idx1", "idx2"]),
|
| 1438 |
+
name="c",
|
| 1439 |
+
)
|
| 1440 |
+
tm.assert_series_equal(result, expected)
|
| 1441 |
+
|
| 1442 |
+
@pytest.mark.parametrize("val", [None, [None], pd.NA, [pd.NA]])
|
| 1443 |
+
def test_iloc_setitem_string_list_na(self, val):
|
| 1444 |
+
# GH#45469
|
| 1445 |
+
df = DataFrame({"a": ["a", "b", "c"]}, dtype="string")
|
| 1446 |
+
df.iloc[[0], :] = val
|
| 1447 |
+
expected = DataFrame({"a": [pd.NA, "b", "c"]}, dtype="string")
|
| 1448 |
+
tm.assert_frame_equal(df, expected)
|
| 1449 |
+
|
| 1450 |
+
@pytest.mark.parametrize("val", [None, pd.NA])
|
| 1451 |
+
def test_iloc_setitem_string_na(self, val):
|
| 1452 |
+
# GH#45469
|
| 1453 |
+
df = DataFrame({"a": ["a", "b", "c"]}, dtype="string")
|
| 1454 |
+
df.iloc[0, :] = val
|
| 1455 |
+
expected = DataFrame({"a": [pd.NA, "b", "c"]}, dtype="string")
|
| 1456 |
+
tm.assert_frame_equal(df, expected)
|
| 1457 |
+
|
| 1458 |
+
@pytest.mark.parametrize("func", [list, Series, np.array])
|
| 1459 |
+
def test_iloc_setitem_ea_null_slice_length_one_list(self, func):
|
| 1460 |
+
# GH#48016
|
| 1461 |
+
df = DataFrame({"a": [1, 2, 3]}, dtype="Int64")
|
| 1462 |
+
df.iloc[:, func([0])] = 5
|
| 1463 |
+
expected = DataFrame({"a": [5, 5, 5]}, dtype="Int64")
|
| 1464 |
+
tm.assert_frame_equal(df, expected)
|
| 1465 |
+
|
| 1466 |
+
def test_loc_named_tuple_for_midx(self):
|
| 1467 |
+
# GH#48124
|
| 1468 |
+
df = DataFrame(
|
| 1469 |
+
index=MultiIndex.from_product(
|
| 1470 |
+
[["A", "B"], ["a", "b", "c"]], names=["first", "second"]
|
| 1471 |
+
)
|
| 1472 |
+
)
|
| 1473 |
+
indexer_tuple = namedtuple("Indexer", df.index.names)
|
| 1474 |
+
idxr = indexer_tuple(first="A", second=["a", "b"])
|
| 1475 |
+
result = df.loc[idxr, :]
|
| 1476 |
+
expected = DataFrame(
|
| 1477 |
+
index=MultiIndex.from_tuples(
|
| 1478 |
+
[("A", "a"), ("A", "b")], names=["first", "second"]
|
| 1479 |
+
)
|
| 1480 |
+
)
|
| 1481 |
+
tm.assert_frame_equal(result, expected)
|
| 1482 |
+
|
| 1483 |
+
@pytest.mark.parametrize("indexer", [["a"], "a"])
|
| 1484 |
+
@pytest.mark.parametrize("col", [{}, {"b": 1}])
|
| 1485 |
+
def test_set_2d_casting_date_to_int(self, col, indexer):
|
| 1486 |
+
# GH#49159
|
| 1487 |
+
df = DataFrame(
|
| 1488 |
+
{"a": [Timestamp("2022-12-29"), Timestamp("2022-12-30")], **col},
|
| 1489 |
+
)
|
| 1490 |
+
df.loc[[1], indexer] = df["a"] + pd.Timedelta(days=1)
|
| 1491 |
+
expected = DataFrame(
|
| 1492 |
+
{"a": [Timestamp("2022-12-29"), Timestamp("2022-12-31")], **col},
|
| 1493 |
+
)
|
| 1494 |
+
tm.assert_frame_equal(df, expected)
|
| 1495 |
+
|
| 1496 |
+
@pytest.mark.parametrize("col", [{}, {"name": "a"}])
|
| 1497 |
+
def test_loc_setitem_reordering_with_all_true_indexer(self, col):
|
| 1498 |
+
# GH#48701
|
| 1499 |
+
n = 17
|
| 1500 |
+
df = DataFrame({**col, "x": range(n), "y": range(n)})
|
| 1501 |
+
expected = df.copy()
|
| 1502 |
+
df.loc[n * [True], ["x", "y"]] = df[["x", "y"]]
|
| 1503 |
+
tm.assert_frame_equal(df, expected)
|
| 1504 |
+
|
| 1505 |
+
def test_loc_rhs_empty_warning(self):
|
| 1506 |
+
# GH48480
|
| 1507 |
+
df = DataFrame(columns=["a", "b"])
|
| 1508 |
+
expected = df.copy()
|
| 1509 |
+
rhs = DataFrame(columns=["a"])
|
| 1510 |
+
with tm.assert_produces_warning(None):
|
| 1511 |
+
df.loc[:, "a"] = rhs
|
| 1512 |
+
tm.assert_frame_equal(df, expected)
|
| 1513 |
+
|
| 1514 |
+
def test_iloc_ea_series_indexer(self):
|
| 1515 |
+
# GH#49521
|
| 1516 |
+
df = DataFrame([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
|
| 1517 |
+
indexer = Series([0, 1], dtype="Int64")
|
| 1518 |
+
row_indexer = Series([1], dtype="Int64")
|
| 1519 |
+
result = df.iloc[row_indexer, indexer]
|
| 1520 |
+
expected = DataFrame([[5, 6]], index=[1])
|
| 1521 |
+
tm.assert_frame_equal(result, expected)
|
| 1522 |
+
|
| 1523 |
+
result = df.iloc[row_indexer.values, indexer.values]
|
| 1524 |
+
tm.assert_frame_equal(result, expected)
|
| 1525 |
+
|
| 1526 |
+
def test_iloc_ea_series_indexer_with_na(self):
|
| 1527 |
+
# GH#49521
|
| 1528 |
+
df = DataFrame([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
|
| 1529 |
+
indexer = Series([0, pd.NA], dtype="Int64")
|
| 1530 |
+
msg = "cannot convert"
|
| 1531 |
+
with pytest.raises(ValueError, match=msg):
|
| 1532 |
+
df.iloc[:, indexer]
|
| 1533 |
+
with pytest.raises(ValueError, match=msg):
|
| 1534 |
+
df.iloc[:, indexer.values]
|
| 1535 |
+
|
| 1536 |
+
@pytest.mark.parametrize("indexer", [True, (True,)])
|
| 1537 |
+
@pytest.mark.parametrize("dtype", [bool, "boolean"])
|
| 1538 |
+
def test_loc_bool_multiindex(self, dtype, indexer):
|
| 1539 |
+
# GH#47687
|
| 1540 |
+
midx = MultiIndex.from_arrays(
|
| 1541 |
+
[
|
| 1542 |
+
Series([True, True, False, False], dtype=dtype),
|
| 1543 |
+
Series([True, False, True, False], dtype=dtype),
|
| 1544 |
+
],
|
| 1545 |
+
names=["a", "b"],
|
| 1546 |
+
)
|
| 1547 |
+
df = DataFrame({"c": [1, 2, 3, 4]}, index=midx)
|
| 1548 |
+
with tm.maybe_produces_warning(PerformanceWarning, isinstance(indexer, tuple)):
|
| 1549 |
+
result = df.loc[indexer]
|
| 1550 |
+
expected = DataFrame(
|
| 1551 |
+
{"c": [1, 2]}, index=Index([True, False], name="b", dtype=dtype)
|
| 1552 |
+
)
|
| 1553 |
+
tm.assert_frame_equal(result, expected)
|
| 1554 |
+
|
| 1555 |
+
@pytest.mark.parametrize("utc", [False, True])
|
| 1556 |
+
@pytest.mark.parametrize("indexer", ["date", ["date"]])
|
| 1557 |
+
def test_loc_datetime_assignment_dtype_does_not_change(self, utc, indexer):
|
| 1558 |
+
# GH#49837
|
| 1559 |
+
df = DataFrame(
|
| 1560 |
+
{
|
| 1561 |
+
"date": to_datetime(
|
| 1562 |
+
[datetime(2022, 1, 20), datetime(2022, 1, 22)], utc=utc
|
| 1563 |
+
),
|
| 1564 |
+
"update": [True, False],
|
| 1565 |
+
}
|
| 1566 |
+
)
|
| 1567 |
+
expected = df.copy(deep=True)
|
| 1568 |
+
|
| 1569 |
+
update_df = df[df["update"]]
|
| 1570 |
+
|
| 1571 |
+
df.loc[df["update"], indexer] = update_df["date"]
|
| 1572 |
+
|
| 1573 |
+
tm.assert_frame_equal(df, expected)
|
| 1574 |
+
|
| 1575 |
+
@pytest.mark.parametrize("indexer, idx", [(tm.loc, 1), (tm.iloc, 2)])
|
| 1576 |
+
def test_setitem_value_coercing_dtypes(self, indexer, idx):
|
| 1577 |
+
# GH#50467
|
| 1578 |
+
df = DataFrame([["1", np.nan], ["2", np.nan], ["3", np.nan]], dtype=object)
|
| 1579 |
+
rhs = DataFrame([[1, np.nan], [2, np.nan]])
|
| 1580 |
+
indexer(df)[:idx, :] = rhs
|
| 1581 |
+
expected = DataFrame([[1, np.nan], [2, np.nan], ["3", np.nan]], dtype=object)
|
| 1582 |
+
tm.assert_frame_equal(df, expected)
|
| 1583 |
+
|
| 1584 |
+
|
| 1585 |
+
class TestDataFrameIndexingUInt64:
|
| 1586 |
+
def test_setitem(self):
|
| 1587 |
+
df = DataFrame(
|
| 1588 |
+
{"A": np.arange(3), "B": [2**63, 2**63 + 5, 2**63 + 10]},
|
| 1589 |
+
dtype=np.uint64,
|
| 1590 |
+
)
|
| 1591 |
+
idx = df["A"].rename("foo")
|
| 1592 |
+
|
| 1593 |
+
# setitem
|
| 1594 |
+
assert "C" not in df.columns
|
| 1595 |
+
df["C"] = idx
|
| 1596 |
+
tm.assert_series_equal(df["C"], Series(idx, name="C"))
|
| 1597 |
+
|
| 1598 |
+
assert "D" not in df.columns
|
| 1599 |
+
df["D"] = "foo"
|
| 1600 |
+
df["D"] = idx
|
| 1601 |
+
tm.assert_series_equal(df["D"], Series(idx, name="D"))
|
| 1602 |
+
del df["D"]
|
| 1603 |
+
|
| 1604 |
+
# With NaN: because uint64 has no NaN element,
|
| 1605 |
+
# the column should be cast to object.
|
| 1606 |
+
df2 = df.copy()
|
| 1607 |
+
with tm.assert_produces_warning(FutureWarning, match="incompatible dtype"):
|
| 1608 |
+
df2.iloc[1, 1] = pd.NaT
|
| 1609 |
+
df2.iloc[1, 2] = pd.NaT
|
| 1610 |
+
result = df2["B"]
|
| 1611 |
+
tm.assert_series_equal(notna(result), Series([True, False, True], name="B"))
|
| 1612 |
+
tm.assert_series_equal(
|
| 1613 |
+
df2.dtypes,
|
| 1614 |
+
Series(
|
| 1615 |
+
[np.dtype("uint64"), np.dtype("O"), np.dtype("O")],
|
| 1616 |
+
index=["A", "B", "C"],
|
| 1617 |
+
),
|
| 1618 |
+
)
|
| 1619 |
+
|
| 1620 |
+
|
| 1621 |
+
def test_object_casting_indexing_wraps_datetimelike(using_array_manager):
|
| 1622 |
+
# GH#31649, check the indexing methods all the way down the stack
|
| 1623 |
+
df = DataFrame(
|
| 1624 |
+
{
|
| 1625 |
+
"A": [1, 2],
|
| 1626 |
+
"B": date_range("2000", periods=2),
|
| 1627 |
+
"C": pd.timedelta_range("1 Day", periods=2),
|
| 1628 |
+
}
|
| 1629 |
+
)
|
| 1630 |
+
|
| 1631 |
+
ser = df.loc[0]
|
| 1632 |
+
assert isinstance(ser.values[1], Timestamp)
|
| 1633 |
+
assert isinstance(ser.values[2], pd.Timedelta)
|
| 1634 |
+
|
| 1635 |
+
ser = df.iloc[0]
|
| 1636 |
+
assert isinstance(ser.values[1], Timestamp)
|
| 1637 |
+
assert isinstance(ser.values[2], pd.Timedelta)
|
| 1638 |
+
|
| 1639 |
+
ser = df.xs(0, axis=0)
|
| 1640 |
+
assert isinstance(ser.values[1], Timestamp)
|
| 1641 |
+
assert isinstance(ser.values[2], pd.Timedelta)
|
| 1642 |
+
|
| 1643 |
+
if using_array_manager:
|
| 1644 |
+
# remainder of the test checking BlockManager internals
|
| 1645 |
+
return
|
| 1646 |
+
|
| 1647 |
+
mgr = df._mgr
|
| 1648 |
+
mgr._rebuild_blknos_and_blklocs()
|
| 1649 |
+
arr = mgr.fast_xs(0).array
|
| 1650 |
+
assert isinstance(arr[1], Timestamp)
|
| 1651 |
+
assert isinstance(arr[2], pd.Timedelta)
|
| 1652 |
+
|
| 1653 |
+
blk = mgr.blocks[mgr.blknos[1]]
|
| 1654 |
+
assert blk.dtype == "M8[ns]" # we got the right block
|
| 1655 |
+
val = blk.iget((0, 0))
|
| 1656 |
+
assert isinstance(val, Timestamp)
|
| 1657 |
+
|
| 1658 |
+
blk = mgr.blocks[mgr.blknos[2]]
|
| 1659 |
+
assert blk.dtype == "m8[ns]" # we got the right block
|
| 1660 |
+
val = blk.iget((0, 0))
|
| 1661 |
+
assert isinstance(val, pd.Timedelta)
|
| 1662 |
+
|
| 1663 |
+
|
| 1664 |
+
msg1 = r"Cannot setitem on a Categorical with a new category( \(.*\))?, set the"
|
| 1665 |
+
msg2 = "Cannot set a Categorical with another, without identical categories"
|
| 1666 |
+
|
| 1667 |
+
|
| 1668 |
+
class TestLocILocDataFrameCategorical:
|
| 1669 |
+
@pytest.fixture
|
| 1670 |
+
def orig(self):
|
| 1671 |
+
cats = Categorical(["a", "a", "a", "a", "a", "a", "a"], categories=["a", "b"])
|
| 1672 |
+
idx = Index(["h", "i", "j", "k", "l", "m", "n"])
|
| 1673 |
+
values = [1, 1, 1, 1, 1, 1, 1]
|
| 1674 |
+
orig = DataFrame({"cats": cats, "values": values}, index=idx)
|
| 1675 |
+
return orig
|
| 1676 |
+
|
| 1677 |
+
@pytest.fixture
|
| 1678 |
+
def exp_single_row(self):
|
| 1679 |
+
# The expected values if we change a single row
|
| 1680 |
+
cats1 = Categorical(["a", "a", "b", "a", "a", "a", "a"], categories=["a", "b"])
|
| 1681 |
+
idx1 = Index(["h", "i", "j", "k", "l", "m", "n"])
|
| 1682 |
+
values1 = [1, 1, 2, 1, 1, 1, 1]
|
| 1683 |
+
exp_single_row = DataFrame({"cats": cats1, "values": values1}, index=idx1)
|
| 1684 |
+
return exp_single_row
|
| 1685 |
+
|
| 1686 |
+
@pytest.fixture
|
| 1687 |
+
def exp_multi_row(self):
|
| 1688 |
+
# assign multiple rows (mixed values) (-> array) -> exp_multi_row
|
| 1689 |
+
# changed multiple rows
|
| 1690 |
+
cats2 = Categorical(["a", "a", "b", "b", "a", "a", "a"], categories=["a", "b"])
|
| 1691 |
+
idx2 = Index(["h", "i", "j", "k", "l", "m", "n"])
|
| 1692 |
+
values2 = [1, 1, 2, 2, 1, 1, 1]
|
| 1693 |
+
exp_multi_row = DataFrame({"cats": cats2, "values": values2}, index=idx2)
|
| 1694 |
+
return exp_multi_row
|
| 1695 |
+
|
| 1696 |
+
@pytest.fixture
|
| 1697 |
+
def exp_parts_cats_col(self):
|
| 1698 |
+
# changed part of the cats column
|
| 1699 |
+
cats3 = Categorical(["a", "a", "b", "b", "a", "a", "a"], categories=["a", "b"])
|
| 1700 |
+
idx3 = Index(["h", "i", "j", "k", "l", "m", "n"])
|
| 1701 |
+
values3 = [1, 1, 1, 1, 1, 1, 1]
|
| 1702 |
+
exp_parts_cats_col = DataFrame({"cats": cats3, "values": values3}, index=idx3)
|
| 1703 |
+
return exp_parts_cats_col
|
| 1704 |
+
|
| 1705 |
+
@pytest.fixture
|
| 1706 |
+
def exp_single_cats_value(self):
|
| 1707 |
+
# changed single value in cats col
|
| 1708 |
+
cats4 = Categorical(["a", "a", "b", "a", "a", "a", "a"], categories=["a", "b"])
|
| 1709 |
+
idx4 = Index(["h", "i", "j", "k", "l", "m", "n"])
|
| 1710 |
+
values4 = [1, 1, 1, 1, 1, 1, 1]
|
| 1711 |
+
exp_single_cats_value = DataFrame(
|
| 1712 |
+
{"cats": cats4, "values": values4}, index=idx4
|
| 1713 |
+
)
|
| 1714 |
+
return exp_single_cats_value
|
| 1715 |
+
|
| 1716 |
+
@pytest.mark.parametrize("indexer", [tm.loc, tm.iloc])
|
| 1717 |
+
def test_loc_iloc_setitem_list_of_lists(self, orig, exp_multi_row, indexer):
|
| 1718 |
+
# - assign multiple rows (mixed values) -> exp_multi_row
|
| 1719 |
+
df = orig.copy()
|
| 1720 |
+
|
| 1721 |
+
key = slice(2, 4)
|
| 1722 |
+
if indexer is tm.loc:
|
| 1723 |
+
key = slice("j", "k")
|
| 1724 |
+
|
| 1725 |
+
indexer(df)[key, :] = [["b", 2], ["b", 2]]
|
| 1726 |
+
tm.assert_frame_equal(df, exp_multi_row)
|
| 1727 |
+
|
| 1728 |
+
df = orig.copy()
|
| 1729 |
+
with pytest.raises(TypeError, match=msg1):
|
| 1730 |
+
indexer(df)[key, :] = [["c", 2], ["c", 2]]
|
| 1731 |
+
|
| 1732 |
+
@pytest.mark.parametrize("indexer", [tm.loc, tm.iloc, tm.at, tm.iat])
|
| 1733 |
+
def test_loc_iloc_at_iat_setitem_single_value_in_categories(
|
| 1734 |
+
self, orig, exp_single_cats_value, indexer
|
| 1735 |
+
):
|
| 1736 |
+
# - assign a single value -> exp_single_cats_value
|
| 1737 |
+
df = orig.copy()
|
| 1738 |
+
|
| 1739 |
+
key = (2, 0)
|
| 1740 |
+
if indexer in [tm.loc, tm.at]:
|
| 1741 |
+
key = (df.index[2], df.columns[0])
|
| 1742 |
+
|
| 1743 |
+
# "b" is among the categories for df["cat"}]
|
| 1744 |
+
indexer(df)[key] = "b"
|
| 1745 |
+
tm.assert_frame_equal(df, exp_single_cats_value)
|
| 1746 |
+
|
| 1747 |
+
# "c" is not among the categories for df["cat"]
|
| 1748 |
+
with pytest.raises(TypeError, match=msg1):
|
| 1749 |
+
indexer(df)[key] = "c"
|
| 1750 |
+
|
| 1751 |
+
@pytest.mark.parametrize("indexer", [tm.loc, tm.iloc])
|
| 1752 |
+
def test_loc_iloc_setitem_mask_single_value_in_categories(
|
| 1753 |
+
self, orig, exp_single_cats_value, indexer
|
| 1754 |
+
):
|
| 1755 |
+
# mask with single True
|
| 1756 |
+
df = orig.copy()
|
| 1757 |
+
|
| 1758 |
+
mask = df.index == "j"
|
| 1759 |
+
key = 0
|
| 1760 |
+
if indexer is tm.loc:
|
| 1761 |
+
key = df.columns[key]
|
| 1762 |
+
|
| 1763 |
+
indexer(df)[mask, key] = "b"
|
| 1764 |
+
tm.assert_frame_equal(df, exp_single_cats_value)
|
| 1765 |
+
|
| 1766 |
+
@pytest.mark.parametrize("indexer", [tm.loc, tm.iloc])
|
| 1767 |
+
def test_loc_iloc_setitem_full_row_non_categorical_rhs(
|
| 1768 |
+
self, orig, exp_single_row, indexer
|
| 1769 |
+
):
|
| 1770 |
+
# - assign a complete row (mixed values) -> exp_single_row
|
| 1771 |
+
df = orig.copy()
|
| 1772 |
+
|
| 1773 |
+
key = 2
|
| 1774 |
+
if indexer is tm.loc:
|
| 1775 |
+
key = df.index[2]
|
| 1776 |
+
|
| 1777 |
+
# not categorical dtype, but "b" _is_ among the categories for df["cat"]
|
| 1778 |
+
indexer(df)[key, :] = ["b", 2]
|
| 1779 |
+
tm.assert_frame_equal(df, exp_single_row)
|
| 1780 |
+
|
| 1781 |
+
# "c" is not among the categories for df["cat"]
|
| 1782 |
+
with pytest.raises(TypeError, match=msg1):
|
| 1783 |
+
indexer(df)[key, :] = ["c", 2]
|
| 1784 |
+
|
| 1785 |
+
@pytest.mark.parametrize("indexer", [tm.loc, tm.iloc])
|
| 1786 |
+
def test_loc_iloc_setitem_partial_col_categorical_rhs(
|
| 1787 |
+
self, orig, exp_parts_cats_col, indexer
|
| 1788 |
+
):
|
| 1789 |
+
# assign a part of a column with dtype == categorical ->
|
| 1790 |
+
# exp_parts_cats_col
|
| 1791 |
+
df = orig.copy()
|
| 1792 |
+
|
| 1793 |
+
key = (slice(2, 4), 0)
|
| 1794 |
+
if indexer is tm.loc:
|
| 1795 |
+
key = (slice("j", "k"), df.columns[0])
|
| 1796 |
+
|
| 1797 |
+
# same categories as we currently have in df["cats"]
|
| 1798 |
+
compat = Categorical(["b", "b"], categories=["a", "b"])
|
| 1799 |
+
indexer(df)[key] = compat
|
| 1800 |
+
tm.assert_frame_equal(df, exp_parts_cats_col)
|
| 1801 |
+
|
| 1802 |
+
# categories do not match df["cat"]'s, but "b" is among them
|
| 1803 |
+
semi_compat = Categorical(list("bb"), categories=list("abc"))
|
| 1804 |
+
with pytest.raises(TypeError, match=msg2):
|
| 1805 |
+
# different categories but holdable values
|
| 1806 |
+
# -> not sure if this should fail or pass
|
| 1807 |
+
indexer(df)[key] = semi_compat
|
| 1808 |
+
|
| 1809 |
+
# categories do not match df["cat"]'s, and "c" is not among them
|
| 1810 |
+
incompat = Categorical(list("cc"), categories=list("abc"))
|
| 1811 |
+
with pytest.raises(TypeError, match=msg2):
|
| 1812 |
+
# different values
|
| 1813 |
+
indexer(df)[key] = incompat
|
| 1814 |
+
|
| 1815 |
+
@pytest.mark.parametrize("indexer", [tm.loc, tm.iloc])
|
| 1816 |
+
def test_loc_iloc_setitem_non_categorical_rhs(
|
| 1817 |
+
self, orig, exp_parts_cats_col, indexer
|
| 1818 |
+
):
|
| 1819 |
+
# assign a part of a column with dtype != categorical -> exp_parts_cats_col
|
| 1820 |
+
df = orig.copy()
|
| 1821 |
+
|
| 1822 |
+
key = (slice(2, 4), 0)
|
| 1823 |
+
if indexer is tm.loc:
|
| 1824 |
+
key = (slice("j", "k"), df.columns[0])
|
| 1825 |
+
|
| 1826 |
+
# "b" is among the categories for df["cat"]
|
| 1827 |
+
indexer(df)[key] = ["b", "b"]
|
| 1828 |
+
tm.assert_frame_equal(df, exp_parts_cats_col)
|
| 1829 |
+
|
| 1830 |
+
# "c" not part of the categories
|
| 1831 |
+
with pytest.raises(TypeError, match=msg1):
|
| 1832 |
+
indexer(df)[key] = ["c", "c"]
|
| 1833 |
+
|
| 1834 |
+
@pytest.mark.parametrize("indexer", [tm.getitem, tm.loc, tm.iloc])
|
| 1835 |
+
def test_getitem_preserve_object_index_with_dates(self, indexer):
|
| 1836 |
+
# https://github.com/pandas-dev/pandas/pull/42950 - when selecting a column
|
| 1837 |
+
# from dataframe, don't try to infer object dtype index on Series construction
|
| 1838 |
+
idx = date_range("2012", periods=3).astype(object)
|
| 1839 |
+
df = DataFrame({0: [1, 2, 3]}, index=idx)
|
| 1840 |
+
assert df.index.dtype == object
|
| 1841 |
+
|
| 1842 |
+
if indexer is tm.getitem:
|
| 1843 |
+
ser = indexer(df)[0]
|
| 1844 |
+
else:
|
| 1845 |
+
ser = indexer(df)[:, 0]
|
| 1846 |
+
|
| 1847 |
+
assert ser.index.dtype == object
|
| 1848 |
+
|
| 1849 |
+
def test_loc_on_multiindex_one_level(self):
|
| 1850 |
+
# GH#45779
|
| 1851 |
+
df = DataFrame(
|
| 1852 |
+
data=[[0], [1]],
|
| 1853 |
+
index=MultiIndex.from_tuples([("a",), ("b",)], names=["first"]),
|
| 1854 |
+
)
|
| 1855 |
+
expected = DataFrame(
|
| 1856 |
+
data=[[0]], index=MultiIndex.from_tuples([("a",)], names=["first"])
|
| 1857 |
+
)
|
| 1858 |
+
result = df.loc["a"]
|
| 1859 |
+
tm.assert_frame_equal(result, expected)
|
| 1860 |
+
|
| 1861 |
+
|
| 1862 |
+
class TestDeprecatedIndexers:
|
| 1863 |
+
@pytest.mark.parametrize(
|
| 1864 |
+
"key", [{1}, {1: 1}, ({1}, "a"), ({1: 1}, "a"), (1, {"a"}), (1, {"a": "a"})]
|
| 1865 |
+
)
|
| 1866 |
+
def test_getitem_dict_and_set_deprecated(self, key):
|
| 1867 |
+
# GH#42825 enforced in 2.0
|
| 1868 |
+
df = DataFrame([[1, 2], [3, 4]], columns=["a", "b"])
|
| 1869 |
+
with pytest.raises(TypeError, match="as an indexer is not supported"):
|
| 1870 |
+
df.loc[key]
|
| 1871 |
+
|
| 1872 |
+
@pytest.mark.parametrize(
|
| 1873 |
+
"key",
|
| 1874 |
+
[
|
| 1875 |
+
{1},
|
| 1876 |
+
{1: 1},
|
| 1877 |
+
(({1}, 2), "a"),
|
| 1878 |
+
(({1: 1}, 2), "a"),
|
| 1879 |
+
((1, 2), {"a"}),
|
| 1880 |
+
((1, 2), {"a": "a"}),
|
| 1881 |
+
],
|
| 1882 |
+
)
|
| 1883 |
+
def test_getitem_dict_and_set_deprecated_multiindex(self, key):
|
| 1884 |
+
# GH#42825 enforced in 2.0
|
| 1885 |
+
df = DataFrame(
|
| 1886 |
+
[[1, 2], [3, 4]],
|
| 1887 |
+
columns=["a", "b"],
|
| 1888 |
+
index=MultiIndex.from_tuples([(1, 2), (3, 4)]),
|
| 1889 |
+
)
|
| 1890 |
+
with pytest.raises(TypeError, match="as an indexer is not supported"):
|
| 1891 |
+
df.loc[key]
|
| 1892 |
+
|
| 1893 |
+
@pytest.mark.parametrize(
|
| 1894 |
+
"key", [{1}, {1: 1}, ({1}, "a"), ({1: 1}, "a"), (1, {"a"}), (1, {"a": "a"})]
|
| 1895 |
+
)
|
| 1896 |
+
def test_setitem_dict_and_set_disallowed(self, key):
|
| 1897 |
+
# GH#42825 enforced in 2.0
|
| 1898 |
+
df = DataFrame([[1, 2], [3, 4]], columns=["a", "b"])
|
| 1899 |
+
with pytest.raises(TypeError, match="as an indexer is not supported"):
|
| 1900 |
+
df.loc[key] = 1
|
| 1901 |
+
|
| 1902 |
+
@pytest.mark.parametrize(
|
| 1903 |
+
"key",
|
| 1904 |
+
[
|
| 1905 |
+
{1},
|
| 1906 |
+
{1: 1},
|
| 1907 |
+
(({1}, 2), "a"),
|
| 1908 |
+
(({1: 1}, 2), "a"),
|
| 1909 |
+
((1, 2), {"a"}),
|
| 1910 |
+
((1, 2), {"a": "a"}),
|
| 1911 |
+
],
|
| 1912 |
+
)
|
| 1913 |
+
def test_setitem_dict_and_set_disallowed_multiindex(self, key):
|
| 1914 |
+
# GH#42825 enforced in 2.0
|
| 1915 |
+
df = DataFrame(
|
| 1916 |
+
[[1, 2], [3, 4]],
|
| 1917 |
+
columns=["a", "b"],
|
| 1918 |
+
index=MultiIndex.from_tuples([(1, 2), (3, 4)]),
|
| 1919 |
+
)
|
| 1920 |
+
with pytest.raises(TypeError, match="as an indexer is not supported"):
|
| 1921 |
+
df.loc[key] = 1
|
| 1922 |
+
|
| 1923 |
+
|
| 1924 |
+
def test_adding_new_conditional_column() -> None:
|
| 1925 |
+
# https://github.com/pandas-dev/pandas/issues/55025
|
| 1926 |
+
df = DataFrame({"x": [1]})
|
| 1927 |
+
df.loc[df["x"] == 1, "y"] = "1"
|
| 1928 |
+
expected = DataFrame({"x": [1], "y": ["1"]})
|
| 1929 |
+
tm.assert_frame_equal(df, expected)
|
| 1930 |
+
|
| 1931 |
+
df = DataFrame({"x": [1]})
|
| 1932 |
+
# try inserting something which numpy would store as 'object'
|
| 1933 |
+
value = lambda x: x
|
| 1934 |
+
df.loc[df["x"] == 1, "y"] = value
|
| 1935 |
+
expected = DataFrame({"x": [1], "y": [value]})
|
| 1936 |
+
tm.assert_frame_equal(df, expected)
|
| 1937 |
+
|
| 1938 |
+
|
| 1939 |
+
@pytest.mark.parametrize(
|
| 1940 |
+
("dtype", "infer_string"),
|
| 1941 |
+
[
|
| 1942 |
+
(object, False),
|
| 1943 |
+
("string[pyarrow_numpy]", True),
|
| 1944 |
+
],
|
| 1945 |
+
)
|
| 1946 |
+
def test_adding_new_conditional_column_with_string(dtype, infer_string) -> None:
|
| 1947 |
+
# https://github.com/pandas-dev/pandas/issues/56204
|
| 1948 |
+
pytest.importorskip("pyarrow")
|
| 1949 |
+
|
| 1950 |
+
df = DataFrame({"a": [1, 2], "b": [3, 4]})
|
| 1951 |
+
with pd.option_context("future.infer_string", infer_string):
|
| 1952 |
+
df.loc[df["a"] == 1, "c"] = "1"
|
| 1953 |
+
expected = DataFrame({"a": [1, 2], "b": [3, 4], "c": ["1", float("nan")]}).astype(
|
| 1954 |
+
{"a": "int64", "b": "int64", "c": dtype}
|
| 1955 |
+
)
|
| 1956 |
+
tm.assert_frame_equal(df, expected)
|
| 1957 |
+
|
| 1958 |
+
|
| 1959 |
+
def test_add_new_column_infer_string():
|
| 1960 |
+
# GH#55366
|
| 1961 |
+
pytest.importorskip("pyarrow")
|
| 1962 |
+
df = DataFrame({"x": [1]})
|
| 1963 |
+
with pd.option_context("future.infer_string", True):
|
| 1964 |
+
df.loc[df["x"] == 1, "y"] = "1"
|
| 1965 |
+
expected = DataFrame(
|
| 1966 |
+
{"x": [1], "y": Series(["1"], dtype="string[pyarrow_numpy]")},
|
| 1967 |
+
columns=Index(["x", "y"], dtype=object),
|
| 1968 |
+
)
|
| 1969 |
+
tm.assert_frame_equal(df, expected)
|
| 1970 |
+
|
| 1971 |
+
|
| 1972 |
+
class TestSetitemValidation:
|
| 1973 |
+
# This is adapted from pandas/tests/arrays/masked/test_indexing.py
|
| 1974 |
+
# but checks for warnings instead of errors.
|
| 1975 |
+
def _check_setitem_invalid(self, df, invalid, indexer, warn):
|
| 1976 |
+
msg = "Setting an item of incompatible dtype is deprecated"
|
| 1977 |
+
msg = re.escape(msg)
|
| 1978 |
+
|
| 1979 |
+
orig_df = df.copy()
|
| 1980 |
+
|
| 1981 |
+
# iloc
|
| 1982 |
+
with tm.assert_produces_warning(warn, match=msg):
|
| 1983 |
+
df.iloc[indexer, 0] = invalid
|
| 1984 |
+
df = orig_df.copy()
|
| 1985 |
+
|
| 1986 |
+
# loc
|
| 1987 |
+
with tm.assert_produces_warning(warn, match=msg):
|
| 1988 |
+
df.loc[indexer, "a"] = invalid
|
| 1989 |
+
df = orig_df.copy()
|
| 1990 |
+
|
| 1991 |
+
_invalid_scalars = [
|
| 1992 |
+
1 + 2j,
|
| 1993 |
+
"True",
|
| 1994 |
+
"1",
|
| 1995 |
+
"1.0",
|
| 1996 |
+
pd.NaT,
|
| 1997 |
+
np.datetime64("NaT"),
|
| 1998 |
+
np.timedelta64("NaT"),
|
| 1999 |
+
]
|
| 2000 |
+
_indexers = [0, [0], slice(0, 1), [True, False, False], slice(None, None, None)]
|
| 2001 |
+
|
| 2002 |
+
@pytest.mark.parametrize(
|
| 2003 |
+
"invalid", _invalid_scalars + [1, 1.0, np.int64(1), np.float64(1)]
|
| 2004 |
+
)
|
| 2005 |
+
@pytest.mark.parametrize("indexer", _indexers)
|
| 2006 |
+
def test_setitem_validation_scalar_bool(self, invalid, indexer):
|
| 2007 |
+
df = DataFrame({"a": [True, False, False]}, dtype="bool")
|
| 2008 |
+
self._check_setitem_invalid(df, invalid, indexer, FutureWarning)
|
| 2009 |
+
|
| 2010 |
+
@pytest.mark.parametrize("invalid", _invalid_scalars + [True, 1.5, np.float64(1.5)])
|
| 2011 |
+
@pytest.mark.parametrize("indexer", _indexers)
|
| 2012 |
+
def test_setitem_validation_scalar_int(self, invalid, any_int_numpy_dtype, indexer):
|
| 2013 |
+
df = DataFrame({"a": [1, 2, 3]}, dtype=any_int_numpy_dtype)
|
| 2014 |
+
if isna(invalid) and invalid is not pd.NaT and not np.isnat(invalid):
|
| 2015 |
+
warn = None
|
| 2016 |
+
else:
|
| 2017 |
+
warn = FutureWarning
|
| 2018 |
+
self._check_setitem_invalid(df, invalid, indexer, warn)
|
| 2019 |
+
|
| 2020 |
+
@pytest.mark.parametrize("invalid", _invalid_scalars + [True])
|
| 2021 |
+
@pytest.mark.parametrize("indexer", _indexers)
|
| 2022 |
+
def test_setitem_validation_scalar_float(self, invalid, float_numpy_dtype, indexer):
|
| 2023 |
+
df = DataFrame({"a": [1, 2, None]}, dtype=float_numpy_dtype)
|
| 2024 |
+
self._check_setitem_invalid(df, invalid, indexer, FutureWarning)
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/test_insert.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
test_insert is specifically for the DataFrame.insert method; not to be
|
| 3 |
+
confused with tests with "insert" in their names that are really testing
|
| 4 |
+
__setitem__.
|
| 5 |
+
"""
|
| 6 |
+
import numpy as np
|
| 7 |
+
import pytest
|
| 8 |
+
|
| 9 |
+
from pandas.errors import PerformanceWarning
|
| 10 |
+
|
| 11 |
+
from pandas import (
|
| 12 |
+
DataFrame,
|
| 13 |
+
Index,
|
| 14 |
+
)
|
| 15 |
+
import pandas._testing as tm
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class TestDataFrameInsert:
|
| 19 |
+
def test_insert(self):
|
| 20 |
+
df = DataFrame(
|
| 21 |
+
np.random.default_rng(2).standard_normal((5, 3)),
|
| 22 |
+
index=np.arange(5),
|
| 23 |
+
columns=["c", "b", "a"],
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
df.insert(0, "foo", df["a"])
|
| 27 |
+
tm.assert_index_equal(df.columns, Index(["foo", "c", "b", "a"]))
|
| 28 |
+
tm.assert_series_equal(df["a"], df["foo"], check_names=False)
|
| 29 |
+
|
| 30 |
+
df.insert(2, "bar", df["c"])
|
| 31 |
+
tm.assert_index_equal(df.columns, Index(["foo", "c", "bar", "b", "a"]))
|
| 32 |
+
tm.assert_almost_equal(df["c"], df["bar"], check_names=False)
|
| 33 |
+
|
| 34 |
+
with pytest.raises(ValueError, match="already exists"):
|
| 35 |
+
df.insert(1, "a", df["b"])
|
| 36 |
+
|
| 37 |
+
msg = "cannot insert c, already exists"
|
| 38 |
+
with pytest.raises(ValueError, match=msg):
|
| 39 |
+
df.insert(1, "c", df["b"])
|
| 40 |
+
|
| 41 |
+
df.columns.name = "some_name"
|
| 42 |
+
# preserve columns name field
|
| 43 |
+
df.insert(0, "baz", df["c"])
|
| 44 |
+
assert df.columns.name == "some_name"
|
| 45 |
+
|
| 46 |
+
def test_insert_column_bug_4032(self):
|
| 47 |
+
# GH#4032, inserting a column and renaming causing errors
|
| 48 |
+
df = DataFrame({"b": [1.1, 2.2]})
|
| 49 |
+
|
| 50 |
+
df = df.rename(columns={})
|
| 51 |
+
df.insert(0, "a", [1, 2])
|
| 52 |
+
result = df.rename(columns={})
|
| 53 |
+
|
| 54 |
+
expected = DataFrame([[1, 1.1], [2, 2.2]], columns=["a", "b"])
|
| 55 |
+
tm.assert_frame_equal(result, expected)
|
| 56 |
+
|
| 57 |
+
df.insert(0, "c", [1.3, 2.3])
|
| 58 |
+
result = df.rename(columns={})
|
| 59 |
+
|
| 60 |
+
expected = DataFrame([[1.3, 1, 1.1], [2.3, 2, 2.2]], columns=["c", "a", "b"])
|
| 61 |
+
tm.assert_frame_equal(result, expected)
|
| 62 |
+
|
| 63 |
+
def test_insert_with_columns_dups(self):
|
| 64 |
+
# GH#14291
|
| 65 |
+
df = DataFrame()
|
| 66 |
+
df.insert(0, "A", ["g", "h", "i"], allow_duplicates=True)
|
| 67 |
+
df.insert(0, "A", ["d", "e", "f"], allow_duplicates=True)
|
| 68 |
+
df.insert(0, "A", ["a", "b", "c"], allow_duplicates=True)
|
| 69 |
+
exp = DataFrame(
|
| 70 |
+
[["a", "d", "g"], ["b", "e", "h"], ["c", "f", "i"]], columns=["A", "A", "A"]
|
| 71 |
+
)
|
| 72 |
+
tm.assert_frame_equal(df, exp)
|
| 73 |
+
|
| 74 |
+
def test_insert_item_cache(self, using_array_manager, using_copy_on_write):
|
| 75 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((4, 3)))
|
| 76 |
+
ser = df[0]
|
| 77 |
+
|
| 78 |
+
if using_array_manager:
|
| 79 |
+
expected_warning = None
|
| 80 |
+
else:
|
| 81 |
+
# with BlockManager warn about high fragmentation of single dtype
|
| 82 |
+
expected_warning = PerformanceWarning
|
| 83 |
+
|
| 84 |
+
with tm.assert_produces_warning(expected_warning):
|
| 85 |
+
for n in range(100):
|
| 86 |
+
df[n + 3] = df[1] * n
|
| 87 |
+
|
| 88 |
+
if using_copy_on_write:
|
| 89 |
+
ser.iloc[0] = 99
|
| 90 |
+
assert df.iloc[0, 0] == df[0][0]
|
| 91 |
+
assert df.iloc[0, 0] != 99
|
| 92 |
+
else:
|
| 93 |
+
ser.values[0] = 99
|
| 94 |
+
assert df.iloc[0, 0] == df[0][0]
|
| 95 |
+
assert df.iloc[0, 0] == 99
|
| 96 |
+
|
| 97 |
+
def test_insert_EA_no_warning(self):
|
| 98 |
+
# PerformanceWarning about fragmented frame should not be raised when
|
| 99 |
+
# using EAs (https://github.com/pandas-dev/pandas/issues/44098)
|
| 100 |
+
df = DataFrame(
|
| 101 |
+
np.random.default_rng(2).integers(0, 100, size=(3, 100)), dtype="Int64"
|
| 102 |
+
)
|
| 103 |
+
with tm.assert_produces_warning(None):
|
| 104 |
+
df["a"] = np.array([1, 2, 3])
|
| 105 |
+
|
| 106 |
+
def test_insert_frame(self):
|
| 107 |
+
# GH#42403
|
| 108 |
+
df = DataFrame({"col1": [1, 2], "col2": [3, 4]})
|
| 109 |
+
|
| 110 |
+
msg = (
|
| 111 |
+
"Expected a one-dimensional object, got a DataFrame with 2 columns instead."
|
| 112 |
+
)
|
| 113 |
+
with pytest.raises(ValueError, match=msg):
|
| 114 |
+
df.insert(1, "newcol", df)
|
| 115 |
+
|
| 116 |
+
def test_insert_int64_loc(self):
|
| 117 |
+
# GH#53193
|
| 118 |
+
df = DataFrame({"a": [1, 2]})
|
| 119 |
+
df.insert(np.int64(0), "b", 0)
|
| 120 |
+
tm.assert_frame_equal(df, DataFrame({"b": [0, 0], "a": [1, 2]}))
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/test_mask.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Tests for DataFrame.mask; tests DataFrame.where as a side-effect.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import numpy as np
|
| 6 |
+
|
| 7 |
+
from pandas import (
|
| 8 |
+
NA,
|
| 9 |
+
DataFrame,
|
| 10 |
+
Float64Dtype,
|
| 11 |
+
Series,
|
| 12 |
+
StringDtype,
|
| 13 |
+
Timedelta,
|
| 14 |
+
isna,
|
| 15 |
+
)
|
| 16 |
+
import pandas._testing as tm
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class TestDataFrameMask:
|
| 20 |
+
def test_mask(self):
|
| 21 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((5, 3)))
|
| 22 |
+
cond = df > 0
|
| 23 |
+
|
| 24 |
+
rs = df.where(cond, np.nan)
|
| 25 |
+
tm.assert_frame_equal(rs, df.mask(df <= 0))
|
| 26 |
+
tm.assert_frame_equal(rs, df.mask(~cond))
|
| 27 |
+
|
| 28 |
+
other = DataFrame(np.random.default_rng(2).standard_normal((5, 3)))
|
| 29 |
+
rs = df.where(cond, other)
|
| 30 |
+
tm.assert_frame_equal(rs, df.mask(df <= 0, other))
|
| 31 |
+
tm.assert_frame_equal(rs, df.mask(~cond, other))
|
| 32 |
+
|
| 33 |
+
def test_mask2(self):
|
| 34 |
+
# see GH#21891
|
| 35 |
+
df = DataFrame([1, 2])
|
| 36 |
+
res = df.mask([[True], [False]])
|
| 37 |
+
|
| 38 |
+
exp = DataFrame([np.nan, 2])
|
| 39 |
+
tm.assert_frame_equal(res, exp)
|
| 40 |
+
|
| 41 |
+
def test_mask_inplace(self):
|
| 42 |
+
# GH#8801
|
| 43 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((5, 3)))
|
| 44 |
+
cond = df > 0
|
| 45 |
+
|
| 46 |
+
rdf = df.copy()
|
| 47 |
+
|
| 48 |
+
return_value = rdf.where(cond, inplace=True)
|
| 49 |
+
assert return_value is None
|
| 50 |
+
tm.assert_frame_equal(rdf, df.where(cond))
|
| 51 |
+
tm.assert_frame_equal(rdf, df.mask(~cond))
|
| 52 |
+
|
| 53 |
+
rdf = df.copy()
|
| 54 |
+
return_value = rdf.where(cond, -df, inplace=True)
|
| 55 |
+
assert return_value is None
|
| 56 |
+
tm.assert_frame_equal(rdf, df.where(cond, -df))
|
| 57 |
+
tm.assert_frame_equal(rdf, df.mask(~cond, -df))
|
| 58 |
+
|
| 59 |
+
def test_mask_edge_case_1xN_frame(self):
|
| 60 |
+
# GH#4071
|
| 61 |
+
df = DataFrame([[1, 2]])
|
| 62 |
+
res = df.mask(DataFrame([[True, False]]))
|
| 63 |
+
expec = DataFrame([[np.nan, 2]])
|
| 64 |
+
tm.assert_frame_equal(res, expec)
|
| 65 |
+
|
| 66 |
+
def test_mask_callable(self):
|
| 67 |
+
# GH#12533
|
| 68 |
+
df = DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
| 69 |
+
result = df.mask(lambda x: x > 4, lambda x: x + 1)
|
| 70 |
+
exp = DataFrame([[1, 2, 3], [4, 6, 7], [8, 9, 10]])
|
| 71 |
+
tm.assert_frame_equal(result, exp)
|
| 72 |
+
tm.assert_frame_equal(result, df.mask(df > 4, df + 1))
|
| 73 |
+
|
| 74 |
+
# return ndarray and scalar
|
| 75 |
+
result = df.mask(lambda x: (x % 2 == 0).values, lambda x: 99)
|
| 76 |
+
exp = DataFrame([[1, 99, 3], [99, 5, 99], [7, 99, 9]])
|
| 77 |
+
tm.assert_frame_equal(result, exp)
|
| 78 |
+
tm.assert_frame_equal(result, df.mask(df % 2 == 0, 99))
|
| 79 |
+
|
| 80 |
+
# chain
|
| 81 |
+
result = (df + 2).mask(lambda x: x > 8, lambda x: x + 10)
|
| 82 |
+
exp = DataFrame([[3, 4, 5], [6, 7, 8], [19, 20, 21]])
|
| 83 |
+
tm.assert_frame_equal(result, exp)
|
| 84 |
+
tm.assert_frame_equal(result, (df + 2).mask((df + 2) > 8, (df + 2) + 10))
|
| 85 |
+
|
| 86 |
+
def test_mask_dtype_bool_conversion(self):
|
| 87 |
+
# GH#3733
|
| 88 |
+
df = DataFrame(data=np.random.default_rng(2).standard_normal((100, 50)))
|
| 89 |
+
df = df.where(df > 0) # create nans
|
| 90 |
+
bools = df > 0
|
| 91 |
+
mask = isna(df)
|
| 92 |
+
expected = bools.astype(object).mask(mask)
|
| 93 |
+
result = bools.mask(mask)
|
| 94 |
+
tm.assert_frame_equal(result, expected)
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
def test_mask_stringdtype(frame_or_series):
|
| 98 |
+
# GH 40824
|
| 99 |
+
obj = DataFrame(
|
| 100 |
+
{"A": ["foo", "bar", "baz", NA]},
|
| 101 |
+
index=["id1", "id2", "id3", "id4"],
|
| 102 |
+
dtype=StringDtype(),
|
| 103 |
+
)
|
| 104 |
+
filtered_obj = DataFrame(
|
| 105 |
+
{"A": ["this", "that"]}, index=["id2", "id3"], dtype=StringDtype()
|
| 106 |
+
)
|
| 107 |
+
expected = DataFrame(
|
| 108 |
+
{"A": [NA, "this", "that", NA]},
|
| 109 |
+
index=["id1", "id2", "id3", "id4"],
|
| 110 |
+
dtype=StringDtype(),
|
| 111 |
+
)
|
| 112 |
+
if frame_or_series is Series:
|
| 113 |
+
obj = obj["A"]
|
| 114 |
+
filtered_obj = filtered_obj["A"]
|
| 115 |
+
expected = expected["A"]
|
| 116 |
+
|
| 117 |
+
filter_ser = Series([False, True, True, False])
|
| 118 |
+
result = obj.mask(filter_ser, filtered_obj)
|
| 119 |
+
|
| 120 |
+
tm.assert_equal(result, expected)
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def test_mask_where_dtype_timedelta():
|
| 124 |
+
# https://github.com/pandas-dev/pandas/issues/39548
|
| 125 |
+
df = DataFrame([Timedelta(i, unit="d") for i in range(5)])
|
| 126 |
+
|
| 127 |
+
expected = DataFrame(np.full(5, np.nan, dtype="timedelta64[ns]"))
|
| 128 |
+
tm.assert_frame_equal(df.mask(df.notna()), expected)
|
| 129 |
+
|
| 130 |
+
expected = DataFrame(
|
| 131 |
+
[np.nan, np.nan, np.nan, Timedelta("3 day"), Timedelta("4 day")]
|
| 132 |
+
)
|
| 133 |
+
tm.assert_frame_equal(df.where(df > Timedelta(2, unit="d")), expected)
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
def test_mask_return_dtype():
|
| 137 |
+
# GH#50488
|
| 138 |
+
ser = Series([0.0, 1.0, 2.0, 3.0], dtype=Float64Dtype())
|
| 139 |
+
cond = ~ser.isna()
|
| 140 |
+
other = Series([True, False, True, False])
|
| 141 |
+
excepted = Series([1.0, 0.0, 1.0, 0.0], dtype=ser.dtype)
|
| 142 |
+
result = ser.mask(cond, other)
|
| 143 |
+
tm.assert_series_equal(result, excepted)
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
def test_mask_inplace_no_other():
|
| 147 |
+
# GH#51685
|
| 148 |
+
df = DataFrame({"a": [1.0, 2.0], "b": ["x", "y"]})
|
| 149 |
+
cond = DataFrame({"a": [True, False], "b": [False, True]})
|
| 150 |
+
df.mask(cond, inplace=True)
|
| 151 |
+
expected = DataFrame({"a": [np.nan, 2], "b": ["x", np.nan]})
|
| 152 |
+
tm.assert_frame_equal(df, expected)
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/test_set_value.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
|
| 3 |
+
from pandas.core.dtypes.common import is_float_dtype
|
| 4 |
+
|
| 5 |
+
from pandas import (
|
| 6 |
+
DataFrame,
|
| 7 |
+
isna,
|
| 8 |
+
)
|
| 9 |
+
import pandas._testing as tm
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
class TestSetValue:
|
| 13 |
+
def test_set_value(self, float_frame):
|
| 14 |
+
for idx in float_frame.index:
|
| 15 |
+
for col in float_frame.columns:
|
| 16 |
+
float_frame._set_value(idx, col, 1)
|
| 17 |
+
assert float_frame[col][idx] == 1
|
| 18 |
+
|
| 19 |
+
def test_set_value_resize(self, float_frame, using_infer_string):
|
| 20 |
+
res = float_frame._set_value("foobar", "B", 0)
|
| 21 |
+
assert res is None
|
| 22 |
+
assert float_frame.index[-1] == "foobar"
|
| 23 |
+
assert float_frame._get_value("foobar", "B") == 0
|
| 24 |
+
|
| 25 |
+
float_frame.loc["foobar", "qux"] = 0
|
| 26 |
+
assert float_frame._get_value("foobar", "qux") == 0
|
| 27 |
+
|
| 28 |
+
res = float_frame.copy()
|
| 29 |
+
res._set_value("foobar", "baz", "sam")
|
| 30 |
+
if using_infer_string:
|
| 31 |
+
assert res["baz"].dtype == "string"
|
| 32 |
+
else:
|
| 33 |
+
assert res["baz"].dtype == np.object_
|
| 34 |
+
res = float_frame.copy()
|
| 35 |
+
res._set_value("foobar", "baz", True)
|
| 36 |
+
assert res["baz"].dtype == np.object_
|
| 37 |
+
|
| 38 |
+
res = float_frame.copy()
|
| 39 |
+
res._set_value("foobar", "baz", 5)
|
| 40 |
+
assert is_float_dtype(res["baz"])
|
| 41 |
+
assert isna(res["baz"].drop(["foobar"])).all()
|
| 42 |
+
|
| 43 |
+
with tm.assert_produces_warning(
|
| 44 |
+
FutureWarning, match="Setting an item of incompatible dtype"
|
| 45 |
+
):
|
| 46 |
+
res._set_value("foobar", "baz", "sam")
|
| 47 |
+
assert res.loc["foobar", "baz"] == "sam"
|
| 48 |
+
|
| 49 |
+
def test_set_value_with_index_dtype_change(self):
|
| 50 |
+
df_orig = DataFrame(
|
| 51 |
+
np.random.default_rng(2).standard_normal((3, 3)),
|
| 52 |
+
index=range(3),
|
| 53 |
+
columns=list("ABC"),
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
# this is actually ambiguous as the 2 is interpreted as a positional
|
| 57 |
+
# so column is not created
|
| 58 |
+
df = df_orig.copy()
|
| 59 |
+
df._set_value("C", 2, 1.0)
|
| 60 |
+
assert list(df.index) == list(df_orig.index) + ["C"]
|
| 61 |
+
# assert list(df.columns) == list(df_orig.columns) + [2]
|
| 62 |
+
|
| 63 |
+
df = df_orig.copy()
|
| 64 |
+
df.loc["C", 2] = 1.0
|
| 65 |
+
assert list(df.index) == list(df_orig.index) + ["C"]
|
| 66 |
+
# assert list(df.columns) == list(df_orig.columns) + [2]
|
| 67 |
+
|
| 68 |
+
# create both new
|
| 69 |
+
df = df_orig.copy()
|
| 70 |
+
df._set_value("C", "D", 1.0)
|
| 71 |
+
assert list(df.index) == list(df_orig.index) + ["C"]
|
| 72 |
+
assert list(df.columns) == list(df_orig.columns) + ["D"]
|
| 73 |
+
|
| 74 |
+
df = df_orig.copy()
|
| 75 |
+
df.loc["C", "D"] = 1.0
|
| 76 |
+
assert list(df.index) == list(df_orig.index) + ["C"]
|
| 77 |
+
assert list(df.columns) == list(df_orig.columns) + ["D"]
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/test_setitem.py
ADDED
|
@@ -0,0 +1,1419 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from datetime import datetime
|
| 2 |
+
|
| 3 |
+
import numpy as np
|
| 4 |
+
import pytest
|
| 5 |
+
|
| 6 |
+
import pandas.util._test_decorators as td
|
| 7 |
+
|
| 8 |
+
from pandas.core.dtypes.base import _registry as ea_registry
|
| 9 |
+
from pandas.core.dtypes.common import is_object_dtype
|
| 10 |
+
from pandas.core.dtypes.dtypes import (
|
| 11 |
+
CategoricalDtype,
|
| 12 |
+
DatetimeTZDtype,
|
| 13 |
+
IntervalDtype,
|
| 14 |
+
PeriodDtype,
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
import pandas as pd
|
| 18 |
+
from pandas import (
|
| 19 |
+
Categorical,
|
| 20 |
+
DataFrame,
|
| 21 |
+
DatetimeIndex,
|
| 22 |
+
Index,
|
| 23 |
+
Interval,
|
| 24 |
+
IntervalIndex,
|
| 25 |
+
MultiIndex,
|
| 26 |
+
NaT,
|
| 27 |
+
Period,
|
| 28 |
+
PeriodIndex,
|
| 29 |
+
Series,
|
| 30 |
+
Timestamp,
|
| 31 |
+
cut,
|
| 32 |
+
date_range,
|
| 33 |
+
notna,
|
| 34 |
+
period_range,
|
| 35 |
+
)
|
| 36 |
+
import pandas._testing as tm
|
| 37 |
+
from pandas.core.arrays import SparseArray
|
| 38 |
+
|
| 39 |
+
from pandas.tseries.offsets import BDay
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
class TestDataFrameSetItem:
|
| 43 |
+
def test_setitem_str_subclass(self):
|
| 44 |
+
# GH#37366
|
| 45 |
+
class mystring(str):
|
| 46 |
+
pass
|
| 47 |
+
|
| 48 |
+
data = ["2020-10-22 01:21:00+00:00"]
|
| 49 |
+
index = DatetimeIndex(data)
|
| 50 |
+
df = DataFrame({"a": [1]}, index=index)
|
| 51 |
+
df["b"] = 2
|
| 52 |
+
df[mystring("c")] = 3
|
| 53 |
+
expected = DataFrame({"a": [1], "b": [2], mystring("c"): [3]}, index=index)
|
| 54 |
+
tm.assert_equal(df, expected)
|
| 55 |
+
|
| 56 |
+
@pytest.mark.parametrize(
|
| 57 |
+
"dtype", ["int32", "int64", "uint32", "uint64", "float32", "float64"]
|
| 58 |
+
)
|
| 59 |
+
def test_setitem_dtype(self, dtype, float_frame):
|
| 60 |
+
# Use integers since casting negative floats to uints is undefined
|
| 61 |
+
arr = np.random.default_rng(2).integers(1, 10, len(float_frame))
|
| 62 |
+
|
| 63 |
+
float_frame[dtype] = np.array(arr, dtype=dtype)
|
| 64 |
+
assert float_frame[dtype].dtype.name == dtype
|
| 65 |
+
|
| 66 |
+
def test_setitem_list_not_dataframe(self, float_frame):
|
| 67 |
+
data = np.random.default_rng(2).standard_normal((len(float_frame), 2))
|
| 68 |
+
float_frame[["A", "B"]] = data
|
| 69 |
+
tm.assert_almost_equal(float_frame[["A", "B"]].values, data)
|
| 70 |
+
|
| 71 |
+
def test_setitem_error_msmgs(self):
|
| 72 |
+
# GH 7432
|
| 73 |
+
df = DataFrame(
|
| 74 |
+
{"bar": [1, 2, 3], "baz": ["d", "e", "f"]},
|
| 75 |
+
index=Index(["a", "b", "c"], name="foo"),
|
| 76 |
+
)
|
| 77 |
+
ser = Series(
|
| 78 |
+
["g", "h", "i", "j"],
|
| 79 |
+
index=Index(["a", "b", "c", "a"], name="foo"),
|
| 80 |
+
name="fiz",
|
| 81 |
+
)
|
| 82 |
+
msg = "cannot reindex on an axis with duplicate labels"
|
| 83 |
+
with pytest.raises(ValueError, match=msg):
|
| 84 |
+
df["newcol"] = ser
|
| 85 |
+
|
| 86 |
+
# GH 4107, more descriptive error message
|
| 87 |
+
df = DataFrame(
|
| 88 |
+
np.random.default_rng(2).integers(0, 2, (4, 4)),
|
| 89 |
+
columns=["a", "b", "c", "d"],
|
| 90 |
+
)
|
| 91 |
+
|
| 92 |
+
msg = "Cannot set a DataFrame with multiple columns to the single column gr"
|
| 93 |
+
with pytest.raises(ValueError, match=msg):
|
| 94 |
+
df["gr"] = df.groupby(["b", "c"]).count()
|
| 95 |
+
|
| 96 |
+
# GH 55956, specific message for zero columns
|
| 97 |
+
msg = "Cannot set a DataFrame without columns to the column gr"
|
| 98 |
+
with pytest.raises(ValueError, match=msg):
|
| 99 |
+
df["gr"] = DataFrame()
|
| 100 |
+
|
| 101 |
+
def test_setitem_benchmark(self):
|
| 102 |
+
# from the vb_suite/frame_methods/frame_insert_columns
|
| 103 |
+
N = 10
|
| 104 |
+
K = 5
|
| 105 |
+
df = DataFrame(index=range(N))
|
| 106 |
+
new_col = np.random.default_rng(2).standard_normal(N)
|
| 107 |
+
for i in range(K):
|
| 108 |
+
df[i] = new_col
|
| 109 |
+
expected = DataFrame(np.repeat(new_col, K).reshape(N, K), index=range(N))
|
| 110 |
+
tm.assert_frame_equal(df, expected)
|
| 111 |
+
|
| 112 |
+
def test_setitem_different_dtype(self):
|
| 113 |
+
df = DataFrame(
|
| 114 |
+
np.random.default_rng(2).standard_normal((5, 3)),
|
| 115 |
+
index=np.arange(5),
|
| 116 |
+
columns=["c", "b", "a"],
|
| 117 |
+
)
|
| 118 |
+
df.insert(0, "foo", df["a"])
|
| 119 |
+
df.insert(2, "bar", df["c"])
|
| 120 |
+
|
| 121 |
+
# diff dtype
|
| 122 |
+
|
| 123 |
+
# new item
|
| 124 |
+
df["x"] = df["a"].astype("float32")
|
| 125 |
+
result = df.dtypes
|
| 126 |
+
expected = Series(
|
| 127 |
+
[np.dtype("float64")] * 5 + [np.dtype("float32")],
|
| 128 |
+
index=["foo", "c", "bar", "b", "a", "x"],
|
| 129 |
+
)
|
| 130 |
+
tm.assert_series_equal(result, expected)
|
| 131 |
+
|
| 132 |
+
# replacing current (in different block)
|
| 133 |
+
df["a"] = df["a"].astype("float32")
|
| 134 |
+
result = df.dtypes
|
| 135 |
+
expected = Series(
|
| 136 |
+
[np.dtype("float64")] * 4 + [np.dtype("float32")] * 2,
|
| 137 |
+
index=["foo", "c", "bar", "b", "a", "x"],
|
| 138 |
+
)
|
| 139 |
+
tm.assert_series_equal(result, expected)
|
| 140 |
+
|
| 141 |
+
df["y"] = df["a"].astype("int32")
|
| 142 |
+
result = df.dtypes
|
| 143 |
+
expected = Series(
|
| 144 |
+
[np.dtype("float64")] * 4 + [np.dtype("float32")] * 2 + [np.dtype("int32")],
|
| 145 |
+
index=["foo", "c", "bar", "b", "a", "x", "y"],
|
| 146 |
+
)
|
| 147 |
+
tm.assert_series_equal(result, expected)
|
| 148 |
+
|
| 149 |
+
def test_setitem_empty_columns(self):
|
| 150 |
+
# GH 13522
|
| 151 |
+
df = DataFrame(index=["A", "B", "C"])
|
| 152 |
+
df["X"] = df.index
|
| 153 |
+
df["X"] = ["x", "y", "z"]
|
| 154 |
+
exp = DataFrame(data={"X": ["x", "y", "z"]}, index=["A", "B", "C"])
|
| 155 |
+
tm.assert_frame_equal(df, exp)
|
| 156 |
+
|
| 157 |
+
def test_setitem_dt64_index_empty_columns(self):
|
| 158 |
+
rng = date_range("1/1/2000 00:00:00", "1/1/2000 1:59:50", freq="10s")
|
| 159 |
+
df = DataFrame(index=np.arange(len(rng)))
|
| 160 |
+
|
| 161 |
+
df["A"] = rng
|
| 162 |
+
assert df["A"].dtype == np.dtype("M8[ns]")
|
| 163 |
+
|
| 164 |
+
def test_setitem_timestamp_empty_columns(self):
|
| 165 |
+
# GH#19843
|
| 166 |
+
df = DataFrame(index=range(3))
|
| 167 |
+
df["now"] = Timestamp("20130101", tz="UTC").as_unit("ns")
|
| 168 |
+
|
| 169 |
+
expected = DataFrame(
|
| 170 |
+
[[Timestamp("20130101", tz="UTC")]] * 3, index=[0, 1, 2], columns=["now"]
|
| 171 |
+
)
|
| 172 |
+
tm.assert_frame_equal(df, expected)
|
| 173 |
+
|
| 174 |
+
def test_setitem_wrong_length_categorical_dtype_raises(self):
|
| 175 |
+
# GH#29523
|
| 176 |
+
cat = Categorical.from_codes([0, 1, 1, 0, 1, 2], ["a", "b", "c"])
|
| 177 |
+
df = DataFrame(range(10), columns=["bar"])
|
| 178 |
+
|
| 179 |
+
msg = (
|
| 180 |
+
rf"Length of values \({len(cat)}\) "
|
| 181 |
+
rf"does not match length of index \({len(df)}\)"
|
| 182 |
+
)
|
| 183 |
+
with pytest.raises(ValueError, match=msg):
|
| 184 |
+
df["foo"] = cat
|
| 185 |
+
|
| 186 |
+
def test_setitem_with_sparse_value(self):
|
| 187 |
+
# GH#8131
|
| 188 |
+
df = DataFrame({"c_1": ["a", "b", "c"], "n_1": [1.0, 2.0, 3.0]})
|
| 189 |
+
sp_array = SparseArray([0, 0, 1])
|
| 190 |
+
df["new_column"] = sp_array
|
| 191 |
+
|
| 192 |
+
expected = Series(sp_array, name="new_column")
|
| 193 |
+
tm.assert_series_equal(df["new_column"], expected)
|
| 194 |
+
|
| 195 |
+
def test_setitem_with_unaligned_sparse_value(self):
|
| 196 |
+
df = DataFrame({"c_1": ["a", "b", "c"], "n_1": [1.0, 2.0, 3.0]})
|
| 197 |
+
sp_series = Series(SparseArray([0, 0, 1]), index=[2, 1, 0])
|
| 198 |
+
|
| 199 |
+
df["new_column"] = sp_series
|
| 200 |
+
expected = Series(SparseArray([1, 0, 0]), name="new_column")
|
| 201 |
+
tm.assert_series_equal(df["new_column"], expected)
|
| 202 |
+
|
| 203 |
+
def test_setitem_period_preserves_dtype(self):
|
| 204 |
+
# GH: 26861
|
| 205 |
+
data = [Period("2003-12", "D")]
|
| 206 |
+
result = DataFrame([])
|
| 207 |
+
result["a"] = data
|
| 208 |
+
|
| 209 |
+
expected = DataFrame({"a": data})
|
| 210 |
+
|
| 211 |
+
tm.assert_frame_equal(result, expected)
|
| 212 |
+
|
| 213 |
+
def test_setitem_dict_preserves_dtypes(self):
|
| 214 |
+
# https://github.com/pandas-dev/pandas/issues/34573
|
| 215 |
+
expected = DataFrame(
|
| 216 |
+
{
|
| 217 |
+
"a": Series([0, 1, 2], dtype="int64"),
|
| 218 |
+
"b": Series([1, 2, 3], dtype=float),
|
| 219 |
+
"c": Series([1, 2, 3], dtype=float),
|
| 220 |
+
"d": Series([1, 2, 3], dtype="uint32"),
|
| 221 |
+
}
|
| 222 |
+
)
|
| 223 |
+
df = DataFrame(
|
| 224 |
+
{
|
| 225 |
+
"a": Series([], dtype="int64"),
|
| 226 |
+
"b": Series([], dtype=float),
|
| 227 |
+
"c": Series([], dtype=float),
|
| 228 |
+
"d": Series([], dtype="uint32"),
|
| 229 |
+
}
|
| 230 |
+
)
|
| 231 |
+
for idx, b in enumerate([1, 2, 3]):
|
| 232 |
+
df.loc[df.shape[0]] = {
|
| 233 |
+
"a": int(idx),
|
| 234 |
+
"b": float(b),
|
| 235 |
+
"c": float(b),
|
| 236 |
+
"d": np.uint32(b),
|
| 237 |
+
}
|
| 238 |
+
tm.assert_frame_equal(df, expected)
|
| 239 |
+
|
| 240 |
+
@pytest.mark.parametrize(
|
| 241 |
+
"obj,dtype",
|
| 242 |
+
[
|
| 243 |
+
(Period("2020-01"), PeriodDtype("M")),
|
| 244 |
+
(Interval(left=0, right=5), IntervalDtype("int64", "right")),
|
| 245 |
+
(
|
| 246 |
+
Timestamp("2011-01-01", tz="US/Eastern"),
|
| 247 |
+
DatetimeTZDtype(unit="s", tz="US/Eastern"),
|
| 248 |
+
),
|
| 249 |
+
],
|
| 250 |
+
)
|
| 251 |
+
def test_setitem_extension_types(self, obj, dtype):
|
| 252 |
+
# GH: 34832
|
| 253 |
+
expected = DataFrame({"idx": [1, 2, 3], "obj": Series([obj] * 3, dtype=dtype)})
|
| 254 |
+
|
| 255 |
+
df = DataFrame({"idx": [1, 2, 3]})
|
| 256 |
+
df["obj"] = obj
|
| 257 |
+
|
| 258 |
+
tm.assert_frame_equal(df, expected)
|
| 259 |
+
|
| 260 |
+
@pytest.mark.parametrize(
|
| 261 |
+
"ea_name",
|
| 262 |
+
[
|
| 263 |
+
dtype.name
|
| 264 |
+
for dtype in ea_registry.dtypes
|
| 265 |
+
# property would require instantiation
|
| 266 |
+
if not isinstance(dtype.name, property)
|
| 267 |
+
]
|
| 268 |
+
+ ["datetime64[ns, UTC]", "period[D]"],
|
| 269 |
+
)
|
| 270 |
+
def test_setitem_with_ea_name(self, ea_name):
|
| 271 |
+
# GH 38386
|
| 272 |
+
result = DataFrame([0])
|
| 273 |
+
result[ea_name] = [1]
|
| 274 |
+
expected = DataFrame({0: [0], ea_name: [1]})
|
| 275 |
+
tm.assert_frame_equal(result, expected)
|
| 276 |
+
|
| 277 |
+
def test_setitem_dt64_ndarray_with_NaT_and_diff_time_units(self):
|
| 278 |
+
# GH#7492
|
| 279 |
+
data_ns = np.array([1, "nat"], dtype="datetime64[ns]")
|
| 280 |
+
result = Series(data_ns).to_frame()
|
| 281 |
+
result["new"] = data_ns
|
| 282 |
+
expected = DataFrame({0: [1, None], "new": [1, None]}, dtype="datetime64[ns]")
|
| 283 |
+
tm.assert_frame_equal(result, expected)
|
| 284 |
+
|
| 285 |
+
# OutOfBoundsDatetime error shouldn't occur; as of 2.0 we preserve "M8[s]"
|
| 286 |
+
data_s = np.array([1, "nat"], dtype="datetime64[s]")
|
| 287 |
+
result["new"] = data_s
|
| 288 |
+
tm.assert_series_equal(result[0], expected[0])
|
| 289 |
+
tm.assert_numpy_array_equal(result["new"].to_numpy(), data_s)
|
| 290 |
+
|
| 291 |
+
@pytest.mark.parametrize("unit", ["h", "m", "s", "ms", "D", "M", "Y"])
|
| 292 |
+
def test_frame_setitem_datetime64_col_other_units(self, unit):
|
| 293 |
+
# Check that non-nano dt64 values get cast to dt64 on setitem
|
| 294 |
+
# into a not-yet-existing column
|
| 295 |
+
n = 100
|
| 296 |
+
|
| 297 |
+
dtype = np.dtype(f"M8[{unit}]")
|
| 298 |
+
vals = np.arange(n, dtype=np.int64).view(dtype)
|
| 299 |
+
if unit in ["s", "ms"]:
|
| 300 |
+
# supported unit
|
| 301 |
+
ex_vals = vals
|
| 302 |
+
else:
|
| 303 |
+
# we get the nearest supported units, i.e. "s"
|
| 304 |
+
ex_vals = vals.astype("datetime64[s]")
|
| 305 |
+
|
| 306 |
+
df = DataFrame({"ints": np.arange(n)}, index=np.arange(n))
|
| 307 |
+
df[unit] = vals
|
| 308 |
+
|
| 309 |
+
assert df[unit].dtype == ex_vals.dtype
|
| 310 |
+
assert (df[unit].values == ex_vals).all()
|
| 311 |
+
|
| 312 |
+
@pytest.mark.parametrize("unit", ["h", "m", "s", "ms", "D", "M", "Y"])
|
| 313 |
+
def test_frame_setitem_existing_datetime64_col_other_units(self, unit):
|
| 314 |
+
# Check that non-nano dt64 values get cast to dt64 on setitem
|
| 315 |
+
# into an already-existing dt64 column
|
| 316 |
+
n = 100
|
| 317 |
+
|
| 318 |
+
dtype = np.dtype(f"M8[{unit}]")
|
| 319 |
+
vals = np.arange(n, dtype=np.int64).view(dtype)
|
| 320 |
+
ex_vals = vals.astype("datetime64[ns]")
|
| 321 |
+
|
| 322 |
+
df = DataFrame({"ints": np.arange(n)}, index=np.arange(n))
|
| 323 |
+
df["dates"] = np.arange(n, dtype=np.int64).view("M8[ns]")
|
| 324 |
+
|
| 325 |
+
# We overwrite existing dt64 column with new, non-nano dt64 vals
|
| 326 |
+
df["dates"] = vals
|
| 327 |
+
assert (df["dates"].values == ex_vals).all()
|
| 328 |
+
|
| 329 |
+
def test_setitem_dt64tz(self, timezone_frame, using_copy_on_write):
|
| 330 |
+
df = timezone_frame
|
| 331 |
+
idx = df["B"].rename("foo")
|
| 332 |
+
|
| 333 |
+
# setitem
|
| 334 |
+
df["C"] = idx
|
| 335 |
+
tm.assert_series_equal(df["C"], Series(idx, name="C"))
|
| 336 |
+
|
| 337 |
+
df["D"] = "foo"
|
| 338 |
+
df["D"] = idx
|
| 339 |
+
tm.assert_series_equal(df["D"], Series(idx, name="D"))
|
| 340 |
+
del df["D"]
|
| 341 |
+
|
| 342 |
+
# assert that A & C are not sharing the same base (e.g. they
|
| 343 |
+
# are copies)
|
| 344 |
+
# Note: This does not hold with Copy on Write (because of lazy copying)
|
| 345 |
+
v1 = df._mgr.arrays[1]
|
| 346 |
+
v2 = df._mgr.arrays[2]
|
| 347 |
+
tm.assert_extension_array_equal(v1, v2)
|
| 348 |
+
v1base = v1._ndarray.base
|
| 349 |
+
v2base = v2._ndarray.base
|
| 350 |
+
if not using_copy_on_write:
|
| 351 |
+
assert v1base is None or (id(v1base) != id(v2base))
|
| 352 |
+
else:
|
| 353 |
+
assert id(v1base) == id(v2base)
|
| 354 |
+
|
| 355 |
+
# with nan
|
| 356 |
+
df2 = df.copy()
|
| 357 |
+
df2.iloc[1, 1] = NaT
|
| 358 |
+
df2.iloc[1, 2] = NaT
|
| 359 |
+
result = df2["B"]
|
| 360 |
+
tm.assert_series_equal(notna(result), Series([True, False, True], name="B"))
|
| 361 |
+
tm.assert_series_equal(df2.dtypes, df.dtypes)
|
| 362 |
+
|
| 363 |
+
def test_setitem_periodindex(self):
|
| 364 |
+
rng = period_range("1/1/2000", periods=5, name="index")
|
| 365 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((5, 3)), index=rng)
|
| 366 |
+
|
| 367 |
+
df["Index"] = rng
|
| 368 |
+
rs = Index(df["Index"])
|
| 369 |
+
tm.assert_index_equal(rs, rng, check_names=False)
|
| 370 |
+
assert rs.name == "Index"
|
| 371 |
+
assert rng.name == "index"
|
| 372 |
+
|
| 373 |
+
rs = df.reset_index().set_index("index")
|
| 374 |
+
assert isinstance(rs.index, PeriodIndex)
|
| 375 |
+
tm.assert_index_equal(rs.index, rng)
|
| 376 |
+
|
| 377 |
+
def test_setitem_complete_column_with_array(self):
|
| 378 |
+
# GH#37954
|
| 379 |
+
df = DataFrame({"a": ["one", "two", "three"], "b": [1, 2, 3]})
|
| 380 |
+
arr = np.array([[1, 1], [3, 1], [5, 1]])
|
| 381 |
+
df[["c", "d"]] = arr
|
| 382 |
+
expected = DataFrame(
|
| 383 |
+
{
|
| 384 |
+
"a": ["one", "two", "three"],
|
| 385 |
+
"b": [1, 2, 3],
|
| 386 |
+
"c": [1, 3, 5],
|
| 387 |
+
"d": [1, 1, 1],
|
| 388 |
+
}
|
| 389 |
+
)
|
| 390 |
+
expected["c"] = expected["c"].astype(arr.dtype)
|
| 391 |
+
expected["d"] = expected["d"].astype(arr.dtype)
|
| 392 |
+
assert expected["c"].dtype == arr.dtype
|
| 393 |
+
assert expected["d"].dtype == arr.dtype
|
| 394 |
+
tm.assert_frame_equal(df, expected)
|
| 395 |
+
|
| 396 |
+
def test_setitem_period_d_dtype(self):
|
| 397 |
+
# GH 39763
|
| 398 |
+
rng = period_range("2016-01-01", periods=9, freq="D", name="A")
|
| 399 |
+
result = DataFrame(rng)
|
| 400 |
+
expected = DataFrame(
|
| 401 |
+
{"A": ["NaT", "NaT", "NaT", "NaT", "NaT", "NaT", "NaT", "NaT", "NaT"]},
|
| 402 |
+
dtype="period[D]",
|
| 403 |
+
)
|
| 404 |
+
result.iloc[:] = rng._na_value
|
| 405 |
+
tm.assert_frame_equal(result, expected)
|
| 406 |
+
|
| 407 |
+
@pytest.mark.parametrize("dtype", ["f8", "i8", "u8"])
|
| 408 |
+
def test_setitem_bool_with_numeric_index(self, dtype):
|
| 409 |
+
# GH#36319
|
| 410 |
+
cols = Index([1, 2, 3], dtype=dtype)
|
| 411 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((3, 3)), columns=cols)
|
| 412 |
+
|
| 413 |
+
df[False] = ["a", "b", "c"]
|
| 414 |
+
|
| 415 |
+
expected_cols = Index([1, 2, 3, False], dtype=object)
|
| 416 |
+
if dtype == "f8":
|
| 417 |
+
expected_cols = Index([1.0, 2.0, 3.0, False], dtype=object)
|
| 418 |
+
|
| 419 |
+
tm.assert_index_equal(df.columns, expected_cols)
|
| 420 |
+
|
| 421 |
+
@pytest.mark.parametrize("indexer", ["B", ["B"]])
|
| 422 |
+
def test_setitem_frame_length_0_str_key(self, indexer):
|
| 423 |
+
# GH#38831
|
| 424 |
+
df = DataFrame(columns=["A", "B"])
|
| 425 |
+
other = DataFrame({"B": [1, 2]})
|
| 426 |
+
df[indexer] = other
|
| 427 |
+
expected = DataFrame({"A": [np.nan] * 2, "B": [1, 2]})
|
| 428 |
+
expected["A"] = expected["A"].astype("object")
|
| 429 |
+
tm.assert_frame_equal(df, expected)
|
| 430 |
+
|
| 431 |
+
def test_setitem_frame_duplicate_columns(self):
|
| 432 |
+
# GH#15695
|
| 433 |
+
cols = ["A", "B", "C"] * 2
|
| 434 |
+
df = DataFrame(index=range(3), columns=cols)
|
| 435 |
+
df.loc[0, "A"] = (0, 3)
|
| 436 |
+
df.loc[:, "B"] = (1, 4)
|
| 437 |
+
df["C"] = (2, 5)
|
| 438 |
+
expected = DataFrame(
|
| 439 |
+
[
|
| 440 |
+
[0, 1, 2, 3, 4, 5],
|
| 441 |
+
[np.nan, 1, 2, np.nan, 4, 5],
|
| 442 |
+
[np.nan, 1, 2, np.nan, 4, 5],
|
| 443 |
+
],
|
| 444 |
+
dtype="object",
|
| 445 |
+
)
|
| 446 |
+
|
| 447 |
+
# set these with unique columns to be extra-unambiguous
|
| 448 |
+
expected[2] = expected[2].astype(np.int64)
|
| 449 |
+
expected[5] = expected[5].astype(np.int64)
|
| 450 |
+
expected.columns = cols
|
| 451 |
+
|
| 452 |
+
tm.assert_frame_equal(df, expected)
|
| 453 |
+
|
| 454 |
+
def test_setitem_frame_duplicate_columns_size_mismatch(self):
|
| 455 |
+
# GH#39510
|
| 456 |
+
cols = ["A", "B", "C"] * 2
|
| 457 |
+
df = DataFrame(index=range(3), columns=cols)
|
| 458 |
+
with pytest.raises(ValueError, match="Columns must be same length as key"):
|
| 459 |
+
df[["A"]] = (0, 3, 5)
|
| 460 |
+
|
| 461 |
+
df2 = df.iloc[:, :3] # unique columns
|
| 462 |
+
with pytest.raises(ValueError, match="Columns must be same length as key"):
|
| 463 |
+
df2[["A"]] = (0, 3, 5)
|
| 464 |
+
|
| 465 |
+
@pytest.mark.parametrize("cols", [["a", "b", "c"], ["a", "a", "a"]])
|
| 466 |
+
def test_setitem_df_wrong_column_number(self, cols):
|
| 467 |
+
# GH#38604
|
| 468 |
+
df = DataFrame([[1, 2, 3]], columns=cols)
|
| 469 |
+
rhs = DataFrame([[10, 11]], columns=["d", "e"])
|
| 470 |
+
msg = "Columns must be same length as key"
|
| 471 |
+
with pytest.raises(ValueError, match=msg):
|
| 472 |
+
df["a"] = rhs
|
| 473 |
+
|
| 474 |
+
def test_setitem_listlike_indexer_duplicate_columns(self):
|
| 475 |
+
# GH#38604
|
| 476 |
+
df = DataFrame([[1, 2, 3]], columns=["a", "b", "b"])
|
| 477 |
+
rhs = DataFrame([[10, 11, 12]], columns=["a", "b", "b"])
|
| 478 |
+
df[["a", "b"]] = rhs
|
| 479 |
+
expected = DataFrame([[10, 11, 12]], columns=["a", "b", "b"])
|
| 480 |
+
tm.assert_frame_equal(df, expected)
|
| 481 |
+
|
| 482 |
+
df[["c", "b"]] = rhs
|
| 483 |
+
expected = DataFrame([[10, 11, 12, 10]], columns=["a", "b", "b", "c"])
|
| 484 |
+
tm.assert_frame_equal(df, expected)
|
| 485 |
+
|
| 486 |
+
def test_setitem_listlike_indexer_duplicate_columns_not_equal_length(self):
|
| 487 |
+
# GH#39403
|
| 488 |
+
df = DataFrame([[1, 2, 3]], columns=["a", "b", "b"])
|
| 489 |
+
rhs = DataFrame([[10, 11]], columns=["a", "b"])
|
| 490 |
+
msg = "Columns must be same length as key"
|
| 491 |
+
with pytest.raises(ValueError, match=msg):
|
| 492 |
+
df[["a", "b"]] = rhs
|
| 493 |
+
|
| 494 |
+
def test_setitem_intervals(self):
|
| 495 |
+
df = DataFrame({"A": range(10)})
|
| 496 |
+
ser = cut(df["A"], 5)
|
| 497 |
+
assert isinstance(ser.cat.categories, IntervalIndex)
|
| 498 |
+
|
| 499 |
+
# B & D end up as Categoricals
|
| 500 |
+
# the remainder are converted to in-line objects
|
| 501 |
+
# containing an IntervalIndex.values
|
| 502 |
+
df["B"] = ser
|
| 503 |
+
df["C"] = np.array(ser)
|
| 504 |
+
df["D"] = ser.values
|
| 505 |
+
df["E"] = np.array(ser.values)
|
| 506 |
+
df["F"] = ser.astype(object)
|
| 507 |
+
|
| 508 |
+
assert isinstance(df["B"].dtype, CategoricalDtype)
|
| 509 |
+
assert isinstance(df["B"].cat.categories.dtype, IntervalDtype)
|
| 510 |
+
assert isinstance(df["D"].dtype, CategoricalDtype)
|
| 511 |
+
assert isinstance(df["D"].cat.categories.dtype, IntervalDtype)
|
| 512 |
+
|
| 513 |
+
# These go through the Series constructor and so get inferred back
|
| 514 |
+
# to IntervalDtype
|
| 515 |
+
assert isinstance(df["C"].dtype, IntervalDtype)
|
| 516 |
+
assert isinstance(df["E"].dtype, IntervalDtype)
|
| 517 |
+
|
| 518 |
+
# But the Series constructor doesn't do inference on Series objects,
|
| 519 |
+
# so setting df["F"] doesn't get cast back to IntervalDtype
|
| 520 |
+
assert is_object_dtype(df["F"])
|
| 521 |
+
|
| 522 |
+
# they compare equal as Index
|
| 523 |
+
# when converted to numpy objects
|
| 524 |
+
c = lambda x: Index(np.array(x))
|
| 525 |
+
tm.assert_index_equal(c(df.B), c(df.B))
|
| 526 |
+
tm.assert_index_equal(c(df.B), c(df.C), check_names=False)
|
| 527 |
+
tm.assert_index_equal(c(df.B), c(df.D), check_names=False)
|
| 528 |
+
tm.assert_index_equal(c(df.C), c(df.D), check_names=False)
|
| 529 |
+
|
| 530 |
+
# B & D are the same Series
|
| 531 |
+
tm.assert_series_equal(df["B"], df["B"])
|
| 532 |
+
tm.assert_series_equal(df["B"], df["D"], check_names=False)
|
| 533 |
+
|
| 534 |
+
# C & E are the same Series
|
| 535 |
+
tm.assert_series_equal(df["C"], df["C"])
|
| 536 |
+
tm.assert_series_equal(df["C"], df["E"], check_names=False)
|
| 537 |
+
|
| 538 |
+
def test_setitem_categorical(self):
|
| 539 |
+
# GH#35369
|
| 540 |
+
df = DataFrame({"h": Series(list("mn")).astype("category")})
|
| 541 |
+
df.h = df.h.cat.reorder_categories(["n", "m"])
|
| 542 |
+
expected = DataFrame(
|
| 543 |
+
{"h": Categorical(["m", "n"]).reorder_categories(["n", "m"])}
|
| 544 |
+
)
|
| 545 |
+
tm.assert_frame_equal(df, expected)
|
| 546 |
+
|
| 547 |
+
def test_setitem_with_empty_listlike(self):
|
| 548 |
+
# GH#17101
|
| 549 |
+
index = Index([], name="idx")
|
| 550 |
+
result = DataFrame(columns=["A"], index=index)
|
| 551 |
+
result["A"] = []
|
| 552 |
+
expected = DataFrame(columns=["A"], index=index)
|
| 553 |
+
tm.assert_index_equal(result.index, expected.index)
|
| 554 |
+
|
| 555 |
+
@pytest.mark.parametrize(
|
| 556 |
+
"cols, values, expected",
|
| 557 |
+
[
|
| 558 |
+
(["C", "D", "D", "a"], [1, 2, 3, 4], 4), # with duplicates
|
| 559 |
+
(["D", "C", "D", "a"], [1, 2, 3, 4], 4), # mixed order
|
| 560 |
+
(["C", "B", "B", "a"], [1, 2, 3, 4], 4), # other duplicate cols
|
| 561 |
+
(["C", "B", "a"], [1, 2, 3], 3), # no duplicates
|
| 562 |
+
(["B", "C", "a"], [3, 2, 1], 1), # alphabetical order
|
| 563 |
+
(["C", "a", "B"], [3, 2, 1], 2), # in the middle
|
| 564 |
+
],
|
| 565 |
+
)
|
| 566 |
+
def test_setitem_same_column(self, cols, values, expected):
|
| 567 |
+
# GH#23239
|
| 568 |
+
df = DataFrame([values], columns=cols)
|
| 569 |
+
df["a"] = df["a"]
|
| 570 |
+
result = df["a"].values[0]
|
| 571 |
+
assert result == expected
|
| 572 |
+
|
| 573 |
+
def test_setitem_multi_index(self):
|
| 574 |
+
# GH#7655, test that assigning to a sub-frame of a frame
|
| 575 |
+
# with multi-index columns aligns both rows and columns
|
| 576 |
+
it = ["jim", "joe", "jolie"], ["first", "last"], ["left", "center", "right"]
|
| 577 |
+
|
| 578 |
+
cols = MultiIndex.from_product(it)
|
| 579 |
+
index = date_range("20141006", periods=20)
|
| 580 |
+
vals = np.random.default_rng(2).integers(1, 1000, (len(index), len(cols)))
|
| 581 |
+
df = DataFrame(vals, columns=cols, index=index)
|
| 582 |
+
|
| 583 |
+
i, j = df.index.values.copy(), it[-1][:]
|
| 584 |
+
|
| 585 |
+
np.random.default_rng(2).shuffle(i)
|
| 586 |
+
df["jim"] = df["jolie"].loc[i, ::-1]
|
| 587 |
+
tm.assert_frame_equal(df["jim"], df["jolie"])
|
| 588 |
+
|
| 589 |
+
np.random.default_rng(2).shuffle(j)
|
| 590 |
+
df[("joe", "first")] = df[("jolie", "last")].loc[i, j]
|
| 591 |
+
tm.assert_frame_equal(df[("joe", "first")], df[("jolie", "last")])
|
| 592 |
+
|
| 593 |
+
np.random.default_rng(2).shuffle(j)
|
| 594 |
+
df[("joe", "last")] = df[("jolie", "first")].loc[i, j]
|
| 595 |
+
tm.assert_frame_equal(df[("joe", "last")], df[("jolie", "first")])
|
| 596 |
+
|
| 597 |
+
@pytest.mark.parametrize(
|
| 598 |
+
"columns,box,expected",
|
| 599 |
+
[
|
| 600 |
+
(
|
| 601 |
+
["A", "B", "C", "D"],
|
| 602 |
+
7,
|
| 603 |
+
DataFrame(
|
| 604 |
+
[[7, 7, 7, 7], [7, 7, 7, 7], [7, 7, 7, 7]],
|
| 605 |
+
columns=["A", "B", "C", "D"],
|
| 606 |
+
),
|
| 607 |
+
),
|
| 608 |
+
(
|
| 609 |
+
["C", "D"],
|
| 610 |
+
[7, 8],
|
| 611 |
+
DataFrame(
|
| 612 |
+
[[1, 2, 7, 8], [3, 4, 7, 8], [5, 6, 7, 8]],
|
| 613 |
+
columns=["A", "B", "C", "D"],
|
| 614 |
+
),
|
| 615 |
+
),
|
| 616 |
+
(
|
| 617 |
+
["A", "B", "C"],
|
| 618 |
+
np.array([7, 8, 9], dtype=np.int64),
|
| 619 |
+
DataFrame([[7, 8, 9], [7, 8, 9], [7, 8, 9]], columns=["A", "B", "C"]),
|
| 620 |
+
),
|
| 621 |
+
(
|
| 622 |
+
["B", "C", "D"],
|
| 623 |
+
[[7, 8, 9], [10, 11, 12], [13, 14, 15]],
|
| 624 |
+
DataFrame(
|
| 625 |
+
[[1, 7, 8, 9], [3, 10, 11, 12], [5, 13, 14, 15]],
|
| 626 |
+
columns=["A", "B", "C", "D"],
|
| 627 |
+
),
|
| 628 |
+
),
|
| 629 |
+
(
|
| 630 |
+
["C", "A", "D"],
|
| 631 |
+
np.array([[7, 8, 9], [10, 11, 12], [13, 14, 15]], dtype=np.int64),
|
| 632 |
+
DataFrame(
|
| 633 |
+
[[8, 2, 7, 9], [11, 4, 10, 12], [14, 6, 13, 15]],
|
| 634 |
+
columns=["A", "B", "C", "D"],
|
| 635 |
+
),
|
| 636 |
+
),
|
| 637 |
+
(
|
| 638 |
+
["A", "C"],
|
| 639 |
+
DataFrame([[7, 8], [9, 10], [11, 12]], columns=["A", "C"]),
|
| 640 |
+
DataFrame(
|
| 641 |
+
[[7, 2, 8], [9, 4, 10], [11, 6, 12]], columns=["A", "B", "C"]
|
| 642 |
+
),
|
| 643 |
+
),
|
| 644 |
+
],
|
| 645 |
+
)
|
| 646 |
+
def test_setitem_list_missing_columns(self, columns, box, expected):
|
| 647 |
+
# GH#29334
|
| 648 |
+
df = DataFrame([[1, 2], [3, 4], [5, 6]], columns=["A", "B"])
|
| 649 |
+
df[columns] = box
|
| 650 |
+
tm.assert_frame_equal(df, expected)
|
| 651 |
+
|
| 652 |
+
def test_setitem_list_of_tuples(self, float_frame):
|
| 653 |
+
tuples = list(zip(float_frame["A"], float_frame["B"]))
|
| 654 |
+
float_frame["tuples"] = tuples
|
| 655 |
+
|
| 656 |
+
result = float_frame["tuples"]
|
| 657 |
+
expected = Series(tuples, index=float_frame.index, name="tuples")
|
| 658 |
+
tm.assert_series_equal(result, expected)
|
| 659 |
+
|
| 660 |
+
def test_setitem_iloc_generator(self):
|
| 661 |
+
# GH#39614
|
| 662 |
+
df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
|
| 663 |
+
indexer = (x for x in [1, 2])
|
| 664 |
+
df.iloc[indexer] = 1
|
| 665 |
+
expected = DataFrame({"a": [1, 1, 1], "b": [4, 1, 1]})
|
| 666 |
+
tm.assert_frame_equal(df, expected)
|
| 667 |
+
|
| 668 |
+
def test_setitem_iloc_two_dimensional_generator(self):
|
| 669 |
+
df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
|
| 670 |
+
indexer = (x for x in [1, 2])
|
| 671 |
+
df.iloc[indexer, 1] = 1
|
| 672 |
+
expected = DataFrame({"a": [1, 2, 3], "b": [4, 1, 1]})
|
| 673 |
+
tm.assert_frame_equal(df, expected)
|
| 674 |
+
|
| 675 |
+
def test_setitem_dtypes_bytes_type_to_object(self):
|
| 676 |
+
# GH 20734
|
| 677 |
+
index = Series(name="id", dtype="S24")
|
| 678 |
+
df = DataFrame(index=index)
|
| 679 |
+
df["a"] = Series(name="a", index=index, dtype=np.uint32)
|
| 680 |
+
df["b"] = Series(name="b", index=index, dtype="S64")
|
| 681 |
+
df["c"] = Series(name="c", index=index, dtype="S64")
|
| 682 |
+
df["d"] = Series(name="d", index=index, dtype=np.uint8)
|
| 683 |
+
result = df.dtypes
|
| 684 |
+
expected = Series([np.uint32, object, object, np.uint8], index=list("abcd"))
|
| 685 |
+
tm.assert_series_equal(result, expected)
|
| 686 |
+
|
| 687 |
+
def test_boolean_mask_nullable_int64(self):
|
| 688 |
+
# GH 28928
|
| 689 |
+
result = DataFrame({"a": [3, 4], "b": [5, 6]}).astype(
|
| 690 |
+
{"a": "int64", "b": "Int64"}
|
| 691 |
+
)
|
| 692 |
+
mask = Series(False, index=result.index)
|
| 693 |
+
result.loc[mask, "a"] = result["a"]
|
| 694 |
+
result.loc[mask, "b"] = result["b"]
|
| 695 |
+
expected = DataFrame({"a": [3, 4], "b": [5, 6]}).astype(
|
| 696 |
+
{"a": "int64", "b": "Int64"}
|
| 697 |
+
)
|
| 698 |
+
tm.assert_frame_equal(result, expected)
|
| 699 |
+
|
| 700 |
+
def test_setitem_ea_dtype_rhs_series(self):
|
| 701 |
+
# GH#47425
|
| 702 |
+
df = DataFrame({"a": [1, 2]})
|
| 703 |
+
df["a"] = Series([1, 2], dtype="Int64")
|
| 704 |
+
expected = DataFrame({"a": [1, 2]}, dtype="Int64")
|
| 705 |
+
tm.assert_frame_equal(df, expected)
|
| 706 |
+
|
| 707 |
+
# TODO(ArrayManager) set column with 2d column array, see #44788
|
| 708 |
+
@td.skip_array_manager_not_yet_implemented
|
| 709 |
+
def test_setitem_npmatrix_2d(self):
|
| 710 |
+
# GH#42376
|
| 711 |
+
# for use-case df["x"] = sparse.random((10, 10)).mean(axis=1)
|
| 712 |
+
expected = DataFrame(
|
| 713 |
+
{"np-array": np.ones(10), "np-matrix": np.ones(10)}, index=np.arange(10)
|
| 714 |
+
)
|
| 715 |
+
|
| 716 |
+
a = np.ones((10, 1))
|
| 717 |
+
df = DataFrame(index=np.arange(10))
|
| 718 |
+
df["np-array"] = a
|
| 719 |
+
|
| 720 |
+
# Instantiation of `np.matrix` gives PendingDeprecationWarning
|
| 721 |
+
with tm.assert_produces_warning(PendingDeprecationWarning):
|
| 722 |
+
df["np-matrix"] = np.matrix(a)
|
| 723 |
+
|
| 724 |
+
tm.assert_frame_equal(df, expected)
|
| 725 |
+
|
| 726 |
+
@pytest.mark.parametrize("vals", [{}, {"d": "a"}])
|
| 727 |
+
def test_setitem_aligning_dict_with_index(self, vals):
|
| 728 |
+
# GH#47216
|
| 729 |
+
df = DataFrame({"a": [1, 2], "b": [3, 4], **vals})
|
| 730 |
+
df.loc[:, "a"] = {1: 100, 0: 200}
|
| 731 |
+
df.loc[:, "c"] = {0: 5, 1: 6}
|
| 732 |
+
df.loc[:, "e"] = {1: 5}
|
| 733 |
+
expected = DataFrame(
|
| 734 |
+
{"a": [200, 100], "b": [3, 4], **vals, "c": [5, 6], "e": [np.nan, 5]}
|
| 735 |
+
)
|
| 736 |
+
tm.assert_frame_equal(df, expected)
|
| 737 |
+
|
| 738 |
+
def test_setitem_rhs_dataframe(self):
|
| 739 |
+
# GH#47578
|
| 740 |
+
df = DataFrame({"a": [1, 2]})
|
| 741 |
+
df["a"] = DataFrame({"a": [10, 11]}, index=[1, 2])
|
| 742 |
+
expected = DataFrame({"a": [np.nan, 10]})
|
| 743 |
+
tm.assert_frame_equal(df, expected)
|
| 744 |
+
|
| 745 |
+
df = DataFrame({"a": [1, 2]})
|
| 746 |
+
df.isetitem(0, DataFrame({"a": [10, 11]}, index=[1, 2]))
|
| 747 |
+
tm.assert_frame_equal(df, expected)
|
| 748 |
+
|
| 749 |
+
def test_setitem_frame_overwrite_with_ea_dtype(self, any_numeric_ea_dtype):
|
| 750 |
+
# GH#46896
|
| 751 |
+
df = DataFrame(columns=["a", "b"], data=[[1, 2], [3, 4]])
|
| 752 |
+
df["a"] = DataFrame({"a": [10, 11]}, dtype=any_numeric_ea_dtype)
|
| 753 |
+
expected = DataFrame(
|
| 754 |
+
{
|
| 755 |
+
"a": Series([10, 11], dtype=any_numeric_ea_dtype),
|
| 756 |
+
"b": [2, 4],
|
| 757 |
+
}
|
| 758 |
+
)
|
| 759 |
+
tm.assert_frame_equal(df, expected)
|
| 760 |
+
|
| 761 |
+
def test_setitem_string_option_object_index(self):
|
| 762 |
+
# GH#55638
|
| 763 |
+
pytest.importorskip("pyarrow")
|
| 764 |
+
df = DataFrame({"a": [1, 2]})
|
| 765 |
+
with pd.option_context("future.infer_string", True):
|
| 766 |
+
df["b"] = Index(["a", "b"], dtype=object)
|
| 767 |
+
expected = DataFrame({"a": [1, 2], "b": Series(["a", "b"], dtype=object)})
|
| 768 |
+
tm.assert_frame_equal(df, expected)
|
| 769 |
+
|
| 770 |
+
def test_setitem_frame_midx_columns(self):
|
| 771 |
+
# GH#49121
|
| 772 |
+
df = DataFrame({("a", "b"): [10]})
|
| 773 |
+
expected = df.copy()
|
| 774 |
+
col_name = ("a", "b")
|
| 775 |
+
df[col_name] = df[[col_name]]
|
| 776 |
+
tm.assert_frame_equal(df, expected)
|
| 777 |
+
|
| 778 |
+
def test_loc_setitem_ea_dtype(self):
|
| 779 |
+
# GH#55604
|
| 780 |
+
df = DataFrame({"a": np.array([10], dtype="i8")})
|
| 781 |
+
df.loc[:, "a"] = Series([11], dtype="Int64")
|
| 782 |
+
expected = DataFrame({"a": np.array([11], dtype="i8")})
|
| 783 |
+
tm.assert_frame_equal(df, expected)
|
| 784 |
+
|
| 785 |
+
df = DataFrame({"a": np.array([10], dtype="i8")})
|
| 786 |
+
df.iloc[:, 0] = Series([11], dtype="Int64")
|
| 787 |
+
tm.assert_frame_equal(df, expected)
|
| 788 |
+
|
| 789 |
+
def test_setitem_object_inferring(self):
|
| 790 |
+
# GH#56102
|
| 791 |
+
idx = Index([Timestamp("2019-12-31")], dtype=object)
|
| 792 |
+
df = DataFrame({"a": [1]})
|
| 793 |
+
with tm.assert_produces_warning(FutureWarning, match="infer"):
|
| 794 |
+
df.loc[:, "b"] = idx
|
| 795 |
+
with tm.assert_produces_warning(FutureWarning, match="infer"):
|
| 796 |
+
df["c"] = idx
|
| 797 |
+
|
| 798 |
+
expected = DataFrame(
|
| 799 |
+
{
|
| 800 |
+
"a": [1],
|
| 801 |
+
"b": Series([Timestamp("2019-12-31")], dtype="datetime64[ns]"),
|
| 802 |
+
"c": Series([Timestamp("2019-12-31")], dtype="datetime64[ns]"),
|
| 803 |
+
}
|
| 804 |
+
)
|
| 805 |
+
tm.assert_frame_equal(df, expected)
|
| 806 |
+
|
| 807 |
+
|
| 808 |
+
class TestSetitemTZAwareValues:
|
| 809 |
+
@pytest.fixture
|
| 810 |
+
def idx(self):
|
| 811 |
+
naive = DatetimeIndex(["2013-1-1 13:00", "2013-1-2 14:00"], name="B")
|
| 812 |
+
idx = naive.tz_localize("US/Pacific")
|
| 813 |
+
return idx
|
| 814 |
+
|
| 815 |
+
@pytest.fixture
|
| 816 |
+
def expected(self, idx):
|
| 817 |
+
expected = Series(np.array(idx.tolist(), dtype="object"), name="B")
|
| 818 |
+
assert expected.dtype == idx.dtype
|
| 819 |
+
return expected
|
| 820 |
+
|
| 821 |
+
def test_setitem_dt64series(self, idx, expected):
|
| 822 |
+
# convert to utc
|
| 823 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((2, 1)), columns=["A"])
|
| 824 |
+
df["B"] = idx
|
| 825 |
+
df["B"] = idx.to_series(index=[0, 1]).dt.tz_convert(None)
|
| 826 |
+
|
| 827 |
+
result = df["B"]
|
| 828 |
+
comp = Series(idx.tz_convert("UTC").tz_localize(None), name="B")
|
| 829 |
+
tm.assert_series_equal(result, comp)
|
| 830 |
+
|
| 831 |
+
def test_setitem_datetimeindex(self, idx, expected):
|
| 832 |
+
# setting a DataFrame column with a tzaware DTI retains the dtype
|
| 833 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((2, 1)), columns=["A"])
|
| 834 |
+
|
| 835 |
+
# assign to frame
|
| 836 |
+
df["B"] = idx
|
| 837 |
+
result = df["B"]
|
| 838 |
+
tm.assert_series_equal(result, expected)
|
| 839 |
+
|
| 840 |
+
def test_setitem_object_array_of_tzaware_datetimes(self, idx, expected):
|
| 841 |
+
# setting a DataFrame column with a tzaware DTI retains the dtype
|
| 842 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((2, 1)), columns=["A"])
|
| 843 |
+
|
| 844 |
+
# object array of datetimes with a tz
|
| 845 |
+
df["B"] = idx.to_pydatetime()
|
| 846 |
+
result = df["B"]
|
| 847 |
+
tm.assert_series_equal(result, expected)
|
| 848 |
+
|
| 849 |
+
|
| 850 |
+
class TestDataFrameSetItemWithExpansion:
|
| 851 |
+
def test_setitem_listlike_views(self, using_copy_on_write, warn_copy_on_write):
|
| 852 |
+
# GH#38148
|
| 853 |
+
df = DataFrame({"a": [1, 2, 3], "b": [4, 4, 6]})
|
| 854 |
+
|
| 855 |
+
# get one column as a view of df
|
| 856 |
+
ser = df["a"]
|
| 857 |
+
|
| 858 |
+
# add columns with list-like indexer
|
| 859 |
+
df[["c", "d"]] = np.array([[0.1, 0.2], [0.3, 0.4], [0.4, 0.5]])
|
| 860 |
+
|
| 861 |
+
# edit in place the first column to check view semantics
|
| 862 |
+
with tm.assert_cow_warning(warn_copy_on_write):
|
| 863 |
+
df.iloc[0, 0] = 100
|
| 864 |
+
|
| 865 |
+
if using_copy_on_write:
|
| 866 |
+
expected = Series([1, 2, 3], name="a")
|
| 867 |
+
else:
|
| 868 |
+
expected = Series([100, 2, 3], name="a")
|
| 869 |
+
tm.assert_series_equal(ser, expected)
|
| 870 |
+
|
| 871 |
+
def test_setitem_string_column_numpy_dtype_raising(self):
|
| 872 |
+
# GH#39010
|
| 873 |
+
df = DataFrame([[1, 2], [3, 4]])
|
| 874 |
+
df["0 - Name"] = [5, 6]
|
| 875 |
+
expected = DataFrame([[1, 2, 5], [3, 4, 6]], columns=[0, 1, "0 - Name"])
|
| 876 |
+
tm.assert_frame_equal(df, expected)
|
| 877 |
+
|
| 878 |
+
def test_setitem_empty_df_duplicate_columns(self, using_copy_on_write):
|
| 879 |
+
# GH#38521
|
| 880 |
+
df = DataFrame(columns=["a", "b", "b"], dtype="float64")
|
| 881 |
+
df.loc[:, "a"] = list(range(2))
|
| 882 |
+
expected = DataFrame(
|
| 883 |
+
[[0, np.nan, np.nan], [1, np.nan, np.nan]], columns=["a", "b", "b"]
|
| 884 |
+
)
|
| 885 |
+
tm.assert_frame_equal(df, expected)
|
| 886 |
+
|
| 887 |
+
def test_setitem_with_expansion_categorical_dtype(self):
|
| 888 |
+
# assignment
|
| 889 |
+
df = DataFrame(
|
| 890 |
+
{
|
| 891 |
+
"value": np.array(
|
| 892 |
+
np.random.default_rng(2).integers(0, 10000, 100), dtype="int32"
|
| 893 |
+
)
|
| 894 |
+
}
|
| 895 |
+
)
|
| 896 |
+
labels = Categorical([f"{i} - {i + 499}" for i in range(0, 10000, 500)])
|
| 897 |
+
|
| 898 |
+
df = df.sort_values(by=["value"], ascending=True)
|
| 899 |
+
ser = cut(df.value, range(0, 10500, 500), right=False, labels=labels)
|
| 900 |
+
cat = ser.values
|
| 901 |
+
|
| 902 |
+
# setting with a Categorical
|
| 903 |
+
df["D"] = cat
|
| 904 |
+
result = df.dtypes
|
| 905 |
+
expected = Series(
|
| 906 |
+
[np.dtype("int32"), CategoricalDtype(categories=labels, ordered=False)],
|
| 907 |
+
index=["value", "D"],
|
| 908 |
+
)
|
| 909 |
+
tm.assert_series_equal(result, expected)
|
| 910 |
+
|
| 911 |
+
# setting with a Series
|
| 912 |
+
df["E"] = ser
|
| 913 |
+
result = df.dtypes
|
| 914 |
+
expected = Series(
|
| 915 |
+
[
|
| 916 |
+
np.dtype("int32"),
|
| 917 |
+
CategoricalDtype(categories=labels, ordered=False),
|
| 918 |
+
CategoricalDtype(categories=labels, ordered=False),
|
| 919 |
+
],
|
| 920 |
+
index=["value", "D", "E"],
|
| 921 |
+
)
|
| 922 |
+
tm.assert_series_equal(result, expected)
|
| 923 |
+
|
| 924 |
+
result1 = df["D"]
|
| 925 |
+
result2 = df["E"]
|
| 926 |
+
tm.assert_categorical_equal(result1._mgr.array, cat)
|
| 927 |
+
|
| 928 |
+
# sorting
|
| 929 |
+
ser.name = "E"
|
| 930 |
+
tm.assert_series_equal(result2.sort_index(), ser.sort_index())
|
| 931 |
+
|
| 932 |
+
def test_setitem_scalars_no_index(self):
|
| 933 |
+
# GH#16823 / GH#17894
|
| 934 |
+
df = DataFrame()
|
| 935 |
+
df["foo"] = 1
|
| 936 |
+
expected = DataFrame(columns=["foo"]).astype(np.int64)
|
| 937 |
+
tm.assert_frame_equal(df, expected)
|
| 938 |
+
|
| 939 |
+
def test_setitem_newcol_tuple_key(self, float_frame):
|
| 940 |
+
assert (
|
| 941 |
+
"A",
|
| 942 |
+
"B",
|
| 943 |
+
) not in float_frame.columns
|
| 944 |
+
float_frame["A", "B"] = float_frame["A"]
|
| 945 |
+
assert ("A", "B") in float_frame.columns
|
| 946 |
+
|
| 947 |
+
result = float_frame["A", "B"]
|
| 948 |
+
expected = float_frame["A"]
|
| 949 |
+
tm.assert_series_equal(result, expected, check_names=False)
|
| 950 |
+
|
| 951 |
+
def test_frame_setitem_newcol_timestamp(self):
|
| 952 |
+
# GH#2155
|
| 953 |
+
columns = date_range(start="1/1/2012", end="2/1/2012", freq=BDay())
|
| 954 |
+
data = DataFrame(columns=columns, index=range(10))
|
| 955 |
+
t = datetime(2012, 11, 1)
|
| 956 |
+
ts = Timestamp(t)
|
| 957 |
+
data[ts] = np.nan # works, mostly a smoke-test
|
| 958 |
+
assert np.isnan(data[ts]).all()
|
| 959 |
+
|
| 960 |
+
def test_frame_setitem_rangeindex_into_new_col(self):
|
| 961 |
+
# GH#47128
|
| 962 |
+
df = DataFrame({"a": ["a", "b"]})
|
| 963 |
+
df["b"] = df.index
|
| 964 |
+
df.loc[[False, True], "b"] = 100
|
| 965 |
+
result = df.loc[[1], :]
|
| 966 |
+
expected = DataFrame({"a": ["b"], "b": [100]}, index=[1])
|
| 967 |
+
tm.assert_frame_equal(result, expected)
|
| 968 |
+
|
| 969 |
+
def test_setitem_frame_keep_ea_dtype(self, any_numeric_ea_dtype):
|
| 970 |
+
# GH#46896
|
| 971 |
+
df = DataFrame(columns=["a", "b"], data=[[1, 2], [3, 4]])
|
| 972 |
+
df["c"] = DataFrame({"a": [10, 11]}, dtype=any_numeric_ea_dtype)
|
| 973 |
+
expected = DataFrame(
|
| 974 |
+
{
|
| 975 |
+
"a": [1, 3],
|
| 976 |
+
"b": [2, 4],
|
| 977 |
+
"c": Series([10, 11], dtype=any_numeric_ea_dtype),
|
| 978 |
+
}
|
| 979 |
+
)
|
| 980 |
+
tm.assert_frame_equal(df, expected)
|
| 981 |
+
|
| 982 |
+
def test_loc_expansion_with_timedelta_type(self):
|
| 983 |
+
result = DataFrame(columns=list("abc"))
|
| 984 |
+
result.loc[0] = {
|
| 985 |
+
"a": pd.to_timedelta(5, unit="s"),
|
| 986 |
+
"b": pd.to_timedelta(72, unit="s"),
|
| 987 |
+
"c": "23",
|
| 988 |
+
}
|
| 989 |
+
expected = DataFrame(
|
| 990 |
+
[[pd.Timedelta("0 days 00:00:05"), pd.Timedelta("0 days 00:01:12"), "23"]],
|
| 991 |
+
index=Index([0]),
|
| 992 |
+
columns=(["a", "b", "c"]),
|
| 993 |
+
)
|
| 994 |
+
tm.assert_frame_equal(result, expected)
|
| 995 |
+
|
| 996 |
+
|
| 997 |
+
class TestDataFrameSetItemSlicing:
|
| 998 |
+
def test_setitem_slice_position(self):
|
| 999 |
+
# GH#31469
|
| 1000 |
+
df = DataFrame(np.zeros((100, 1)))
|
| 1001 |
+
df[-4:] = 1
|
| 1002 |
+
arr = np.zeros((100, 1))
|
| 1003 |
+
arr[-4:] = 1
|
| 1004 |
+
expected = DataFrame(arr)
|
| 1005 |
+
tm.assert_frame_equal(df, expected)
|
| 1006 |
+
|
| 1007 |
+
@pytest.mark.parametrize("indexer", [tm.setitem, tm.iloc])
|
| 1008 |
+
@pytest.mark.parametrize("box", [Series, np.array, list, pd.array])
|
| 1009 |
+
@pytest.mark.parametrize("n", [1, 2, 3])
|
| 1010 |
+
def test_setitem_slice_indexer_broadcasting_rhs(self, n, box, indexer):
|
| 1011 |
+
# GH#40440
|
| 1012 |
+
df = DataFrame([[1, 3, 5]] + [[2, 4, 6]] * n, columns=["a", "b", "c"])
|
| 1013 |
+
indexer(df)[1:] = box([10, 11, 12])
|
| 1014 |
+
expected = DataFrame([[1, 3, 5]] + [[10, 11, 12]] * n, columns=["a", "b", "c"])
|
| 1015 |
+
tm.assert_frame_equal(df, expected)
|
| 1016 |
+
|
| 1017 |
+
@pytest.mark.parametrize("box", [Series, np.array, list, pd.array])
|
| 1018 |
+
@pytest.mark.parametrize("n", [1, 2, 3])
|
| 1019 |
+
def test_setitem_list_indexer_broadcasting_rhs(self, n, box):
|
| 1020 |
+
# GH#40440
|
| 1021 |
+
df = DataFrame([[1, 3, 5]] + [[2, 4, 6]] * n, columns=["a", "b", "c"])
|
| 1022 |
+
df.iloc[list(range(1, n + 1))] = box([10, 11, 12])
|
| 1023 |
+
expected = DataFrame([[1, 3, 5]] + [[10, 11, 12]] * n, columns=["a", "b", "c"])
|
| 1024 |
+
tm.assert_frame_equal(df, expected)
|
| 1025 |
+
|
| 1026 |
+
@pytest.mark.parametrize("indexer", [tm.setitem, tm.iloc])
|
| 1027 |
+
@pytest.mark.parametrize("box", [Series, np.array, list, pd.array])
|
| 1028 |
+
@pytest.mark.parametrize("n", [1, 2, 3])
|
| 1029 |
+
def test_setitem_slice_broadcasting_rhs_mixed_dtypes(self, n, box, indexer):
|
| 1030 |
+
# GH#40440
|
| 1031 |
+
df = DataFrame(
|
| 1032 |
+
[[1, 3, 5], ["x", "y", "z"]] + [[2, 4, 6]] * n, columns=["a", "b", "c"]
|
| 1033 |
+
)
|
| 1034 |
+
indexer(df)[1:] = box([10, 11, 12])
|
| 1035 |
+
expected = DataFrame(
|
| 1036 |
+
[[1, 3, 5]] + [[10, 11, 12]] * (n + 1),
|
| 1037 |
+
columns=["a", "b", "c"],
|
| 1038 |
+
dtype="object",
|
| 1039 |
+
)
|
| 1040 |
+
tm.assert_frame_equal(df, expected)
|
| 1041 |
+
|
| 1042 |
+
|
| 1043 |
+
class TestDataFrameSetItemCallable:
|
| 1044 |
+
def test_setitem_callable(self):
|
| 1045 |
+
# GH#12533
|
| 1046 |
+
df = DataFrame({"A": [1, 2, 3, 4], "B": [5, 6, 7, 8]})
|
| 1047 |
+
df[lambda x: "A"] = [11, 12, 13, 14]
|
| 1048 |
+
|
| 1049 |
+
exp = DataFrame({"A": [11, 12, 13, 14], "B": [5, 6, 7, 8]})
|
| 1050 |
+
tm.assert_frame_equal(df, exp)
|
| 1051 |
+
|
| 1052 |
+
def test_setitem_other_callable(self):
|
| 1053 |
+
# GH#13299
|
| 1054 |
+
def inc(x):
|
| 1055 |
+
return x + 1
|
| 1056 |
+
|
| 1057 |
+
# Set dtype object straight away to avoid upcast when setting inc below
|
| 1058 |
+
df = DataFrame([[-1, 1], [1, -1]], dtype=object)
|
| 1059 |
+
df[df > 0] = inc
|
| 1060 |
+
|
| 1061 |
+
expected = DataFrame([[-1, inc], [inc, -1]])
|
| 1062 |
+
tm.assert_frame_equal(df, expected)
|
| 1063 |
+
|
| 1064 |
+
|
| 1065 |
+
class TestDataFrameSetItemBooleanMask:
|
| 1066 |
+
@td.skip_array_manager_invalid_test # TODO(ArrayManager) rewrite not using .values
|
| 1067 |
+
@pytest.mark.parametrize(
|
| 1068 |
+
"mask_type",
|
| 1069 |
+
[lambda df: df > np.abs(df) / 2, lambda df: (df > np.abs(df) / 2).values],
|
| 1070 |
+
ids=["dataframe", "array"],
|
| 1071 |
+
)
|
| 1072 |
+
def test_setitem_boolean_mask(self, mask_type, float_frame):
|
| 1073 |
+
# Test for issue #18582
|
| 1074 |
+
df = float_frame.copy()
|
| 1075 |
+
mask = mask_type(df)
|
| 1076 |
+
|
| 1077 |
+
# index with boolean mask
|
| 1078 |
+
result = df.copy()
|
| 1079 |
+
result[mask] = np.nan
|
| 1080 |
+
|
| 1081 |
+
expected = df.values.copy()
|
| 1082 |
+
expected[np.array(mask)] = np.nan
|
| 1083 |
+
expected = DataFrame(expected, index=df.index, columns=df.columns)
|
| 1084 |
+
tm.assert_frame_equal(result, expected)
|
| 1085 |
+
|
| 1086 |
+
@pytest.mark.xfail(reason="Currently empty indexers are treated as all False")
|
| 1087 |
+
@pytest.mark.parametrize("box", [list, np.array, Series])
|
| 1088 |
+
def test_setitem_loc_empty_indexer_raises_with_non_empty_value(self, box):
|
| 1089 |
+
# GH#37672
|
| 1090 |
+
df = DataFrame({"a": ["a"], "b": [1], "c": [1]})
|
| 1091 |
+
if box == Series:
|
| 1092 |
+
indexer = box([], dtype="object")
|
| 1093 |
+
else:
|
| 1094 |
+
indexer = box([])
|
| 1095 |
+
msg = "Must have equal len keys and value when setting with an iterable"
|
| 1096 |
+
with pytest.raises(ValueError, match=msg):
|
| 1097 |
+
df.loc[indexer, ["b"]] = [1]
|
| 1098 |
+
|
| 1099 |
+
@pytest.mark.parametrize("box", [list, np.array, Series])
|
| 1100 |
+
def test_setitem_loc_only_false_indexer_dtype_changed(self, box):
|
| 1101 |
+
# GH#37550
|
| 1102 |
+
# Dtype is only changed when value to set is a Series and indexer is
|
| 1103 |
+
# empty/bool all False
|
| 1104 |
+
df = DataFrame({"a": ["a"], "b": [1], "c": [1]})
|
| 1105 |
+
indexer = box([False])
|
| 1106 |
+
df.loc[indexer, ["b"]] = 10 - df["c"]
|
| 1107 |
+
expected = DataFrame({"a": ["a"], "b": [1], "c": [1]})
|
| 1108 |
+
tm.assert_frame_equal(df, expected)
|
| 1109 |
+
|
| 1110 |
+
df.loc[indexer, ["b"]] = 9
|
| 1111 |
+
tm.assert_frame_equal(df, expected)
|
| 1112 |
+
|
| 1113 |
+
@pytest.mark.parametrize("indexer", [tm.setitem, tm.loc])
|
| 1114 |
+
def test_setitem_boolean_mask_aligning(self, indexer):
|
| 1115 |
+
# GH#39931
|
| 1116 |
+
df = DataFrame({"a": [1, 4, 2, 3], "b": [5, 6, 7, 8]})
|
| 1117 |
+
expected = df.copy()
|
| 1118 |
+
mask = df["a"] >= 3
|
| 1119 |
+
indexer(df)[mask] = indexer(df)[mask].sort_values("a")
|
| 1120 |
+
tm.assert_frame_equal(df, expected)
|
| 1121 |
+
|
| 1122 |
+
def test_setitem_mask_categorical(self):
|
| 1123 |
+
# assign multiple rows (mixed values) (-> array) -> exp_multi_row
|
| 1124 |
+
# changed multiple rows
|
| 1125 |
+
cats2 = Categorical(["a", "a", "b", "b", "a", "a", "a"], categories=["a", "b"])
|
| 1126 |
+
idx2 = Index(["h", "i", "j", "k", "l", "m", "n"])
|
| 1127 |
+
values2 = [1, 1, 2, 2, 1, 1, 1]
|
| 1128 |
+
exp_multi_row = DataFrame({"cats": cats2, "values": values2}, index=idx2)
|
| 1129 |
+
|
| 1130 |
+
catsf = Categorical(
|
| 1131 |
+
["a", "a", "c", "c", "a", "a", "a"], categories=["a", "b", "c"]
|
| 1132 |
+
)
|
| 1133 |
+
idxf = Index(["h", "i", "j", "k", "l", "m", "n"])
|
| 1134 |
+
valuesf = [1, 1, 3, 3, 1, 1, 1]
|
| 1135 |
+
df = DataFrame({"cats": catsf, "values": valuesf}, index=idxf)
|
| 1136 |
+
|
| 1137 |
+
exp_fancy = exp_multi_row.copy()
|
| 1138 |
+
exp_fancy["cats"] = exp_fancy["cats"].cat.set_categories(["a", "b", "c"])
|
| 1139 |
+
|
| 1140 |
+
mask = df["cats"] == "c"
|
| 1141 |
+
df[mask] = ["b", 2]
|
| 1142 |
+
# category c is kept in .categories
|
| 1143 |
+
tm.assert_frame_equal(df, exp_fancy)
|
| 1144 |
+
|
| 1145 |
+
@pytest.mark.parametrize("dtype", ["float", "int64"])
|
| 1146 |
+
@pytest.mark.parametrize("kwargs", [{}, {"index": [1]}, {"columns": ["A"]}])
|
| 1147 |
+
def test_setitem_empty_frame_with_boolean(self, dtype, kwargs):
|
| 1148 |
+
# see GH#10126
|
| 1149 |
+
kwargs["dtype"] = dtype
|
| 1150 |
+
df = DataFrame(**kwargs)
|
| 1151 |
+
|
| 1152 |
+
df2 = df.copy()
|
| 1153 |
+
df[df > df2] = 47
|
| 1154 |
+
tm.assert_frame_equal(df, df2)
|
| 1155 |
+
|
| 1156 |
+
def test_setitem_boolean_indexing(self):
|
| 1157 |
+
idx = list(range(3))
|
| 1158 |
+
cols = ["A", "B", "C"]
|
| 1159 |
+
df1 = DataFrame(
|
| 1160 |
+
index=idx,
|
| 1161 |
+
columns=cols,
|
| 1162 |
+
data=np.array(
|
| 1163 |
+
[[0.0, 0.5, 1.0], [1.5, 2.0, 2.5], [3.0, 3.5, 4.0]], dtype=float
|
| 1164 |
+
),
|
| 1165 |
+
)
|
| 1166 |
+
df2 = DataFrame(index=idx, columns=cols, data=np.ones((len(idx), len(cols))))
|
| 1167 |
+
|
| 1168 |
+
expected = DataFrame(
|
| 1169 |
+
index=idx,
|
| 1170 |
+
columns=cols,
|
| 1171 |
+
data=np.array([[0.0, 0.5, 1.0], [1.5, 2.0, -1], [-1, -1, -1]], dtype=float),
|
| 1172 |
+
)
|
| 1173 |
+
|
| 1174 |
+
df1[df1 > 2.0 * df2] = -1
|
| 1175 |
+
tm.assert_frame_equal(df1, expected)
|
| 1176 |
+
with pytest.raises(ValueError, match="Item wrong length"):
|
| 1177 |
+
df1[df1.index[:-1] > 2] = -1
|
| 1178 |
+
|
| 1179 |
+
def test_loc_setitem_all_false_boolean_two_blocks(self):
|
| 1180 |
+
# GH#40885
|
| 1181 |
+
df = DataFrame({"a": [1, 2], "b": [3, 4], "c": "a"})
|
| 1182 |
+
expected = df.copy()
|
| 1183 |
+
indexer = Series([False, False], name="c")
|
| 1184 |
+
df.loc[indexer, ["b"]] = DataFrame({"b": [5, 6]}, index=[0, 1])
|
| 1185 |
+
tm.assert_frame_equal(df, expected)
|
| 1186 |
+
|
| 1187 |
+
def test_setitem_ea_boolean_mask(self):
|
| 1188 |
+
# GH#47125
|
| 1189 |
+
df = DataFrame([[-1, 2], [3, -4]])
|
| 1190 |
+
expected = DataFrame([[0, 2], [3, 0]])
|
| 1191 |
+
boolean_indexer = DataFrame(
|
| 1192 |
+
{
|
| 1193 |
+
0: Series([True, False], dtype="boolean"),
|
| 1194 |
+
1: Series([pd.NA, True], dtype="boolean"),
|
| 1195 |
+
}
|
| 1196 |
+
)
|
| 1197 |
+
df[boolean_indexer] = 0
|
| 1198 |
+
tm.assert_frame_equal(df, expected)
|
| 1199 |
+
|
| 1200 |
+
|
| 1201 |
+
class TestDataFrameSetitemCopyViewSemantics:
|
| 1202 |
+
def test_setitem_always_copy(self, float_frame):
|
| 1203 |
+
assert "E" not in float_frame.columns
|
| 1204 |
+
s = float_frame["A"].copy()
|
| 1205 |
+
float_frame["E"] = s
|
| 1206 |
+
|
| 1207 |
+
float_frame.iloc[5:10, float_frame.columns.get_loc("E")] = np.nan
|
| 1208 |
+
assert notna(s[5:10]).all()
|
| 1209 |
+
|
| 1210 |
+
@pytest.mark.parametrize("consolidate", [True, False])
|
| 1211 |
+
def test_setitem_partial_column_inplace(
|
| 1212 |
+
self, consolidate, using_array_manager, using_copy_on_write
|
| 1213 |
+
):
|
| 1214 |
+
# This setting should be in-place, regardless of whether frame is
|
| 1215 |
+
# single-block or multi-block
|
| 1216 |
+
# GH#304 this used to be incorrectly not-inplace, in which case
|
| 1217 |
+
# we needed to ensure _item_cache was cleared.
|
| 1218 |
+
|
| 1219 |
+
df = DataFrame(
|
| 1220 |
+
{"x": [1.1, 2.1, 3.1, 4.1], "y": [5.1, 6.1, 7.1, 8.1]}, index=[0, 1, 2, 3]
|
| 1221 |
+
)
|
| 1222 |
+
df.insert(2, "z", np.nan)
|
| 1223 |
+
if not using_array_manager:
|
| 1224 |
+
if consolidate:
|
| 1225 |
+
df._consolidate_inplace()
|
| 1226 |
+
assert len(df._mgr.blocks) == 1
|
| 1227 |
+
else:
|
| 1228 |
+
assert len(df._mgr.blocks) == 2
|
| 1229 |
+
|
| 1230 |
+
zvals = df["z"]._values
|
| 1231 |
+
|
| 1232 |
+
df.loc[2:, "z"] = 42
|
| 1233 |
+
|
| 1234 |
+
expected = Series([np.nan, np.nan, 42, 42], index=df.index, name="z")
|
| 1235 |
+
tm.assert_series_equal(df["z"], expected)
|
| 1236 |
+
|
| 1237 |
+
# check setting occurred in-place
|
| 1238 |
+
if not using_copy_on_write:
|
| 1239 |
+
tm.assert_numpy_array_equal(zvals, expected.values)
|
| 1240 |
+
assert np.shares_memory(zvals, df["z"]._values)
|
| 1241 |
+
|
| 1242 |
+
def test_setitem_duplicate_columns_not_inplace(self):
|
| 1243 |
+
# GH#39510
|
| 1244 |
+
cols = ["A", "B"] * 2
|
| 1245 |
+
df = DataFrame(0.0, index=[0], columns=cols)
|
| 1246 |
+
df_copy = df.copy()
|
| 1247 |
+
df_view = df[:]
|
| 1248 |
+
df["B"] = (2, 5)
|
| 1249 |
+
|
| 1250 |
+
expected = DataFrame([[0.0, 2, 0.0, 5]], columns=cols)
|
| 1251 |
+
tm.assert_frame_equal(df_view, df_copy)
|
| 1252 |
+
tm.assert_frame_equal(df, expected)
|
| 1253 |
+
|
| 1254 |
+
@pytest.mark.parametrize(
|
| 1255 |
+
"value", [1, np.array([[1], [1]], dtype="int64"), [[1], [1]]]
|
| 1256 |
+
)
|
| 1257 |
+
def test_setitem_same_dtype_not_inplace(self, value, using_array_manager):
|
| 1258 |
+
# GH#39510
|
| 1259 |
+
cols = ["A", "B"]
|
| 1260 |
+
df = DataFrame(0, index=[0, 1], columns=cols)
|
| 1261 |
+
df_copy = df.copy()
|
| 1262 |
+
df_view = df[:]
|
| 1263 |
+
df[["B"]] = value
|
| 1264 |
+
|
| 1265 |
+
expected = DataFrame([[0, 1], [0, 1]], columns=cols)
|
| 1266 |
+
tm.assert_frame_equal(df, expected)
|
| 1267 |
+
tm.assert_frame_equal(df_view, df_copy)
|
| 1268 |
+
|
| 1269 |
+
@pytest.mark.parametrize("value", [1.0, np.array([[1.0], [1.0]]), [[1.0], [1.0]]])
|
| 1270 |
+
def test_setitem_listlike_key_scalar_value_not_inplace(self, value):
|
| 1271 |
+
# GH#39510
|
| 1272 |
+
cols = ["A", "B"]
|
| 1273 |
+
df = DataFrame(0, index=[0, 1], columns=cols)
|
| 1274 |
+
df_copy = df.copy()
|
| 1275 |
+
df_view = df[:]
|
| 1276 |
+
df[["B"]] = value
|
| 1277 |
+
|
| 1278 |
+
expected = DataFrame([[0, 1.0], [0, 1.0]], columns=cols)
|
| 1279 |
+
tm.assert_frame_equal(df_view, df_copy)
|
| 1280 |
+
tm.assert_frame_equal(df, expected)
|
| 1281 |
+
|
| 1282 |
+
@pytest.mark.parametrize(
|
| 1283 |
+
"indexer",
|
| 1284 |
+
[
|
| 1285 |
+
"a",
|
| 1286 |
+
["a"],
|
| 1287 |
+
pytest.param(
|
| 1288 |
+
[True, False],
|
| 1289 |
+
marks=pytest.mark.xfail(
|
| 1290 |
+
reason="Boolean indexer incorrectly setting inplace",
|
| 1291 |
+
strict=False, # passing on some builds, no obvious pattern
|
| 1292 |
+
),
|
| 1293 |
+
),
|
| 1294 |
+
],
|
| 1295 |
+
)
|
| 1296 |
+
@pytest.mark.parametrize(
|
| 1297 |
+
"value, set_value",
|
| 1298 |
+
[
|
| 1299 |
+
(1, 5),
|
| 1300 |
+
(1.0, 5.0),
|
| 1301 |
+
(Timestamp("2020-12-31"), Timestamp("2021-12-31")),
|
| 1302 |
+
("a", "b"),
|
| 1303 |
+
],
|
| 1304 |
+
)
|
| 1305 |
+
def test_setitem_not_operating_inplace(self, value, set_value, indexer):
|
| 1306 |
+
# GH#43406
|
| 1307 |
+
df = DataFrame({"a": value}, index=[0, 1])
|
| 1308 |
+
expected = df.copy()
|
| 1309 |
+
view = df[:]
|
| 1310 |
+
df[indexer] = set_value
|
| 1311 |
+
tm.assert_frame_equal(view, expected)
|
| 1312 |
+
|
| 1313 |
+
@td.skip_array_manager_invalid_test
|
| 1314 |
+
def test_setitem_column_update_inplace(
|
| 1315 |
+
self, using_copy_on_write, warn_copy_on_write
|
| 1316 |
+
):
|
| 1317 |
+
# https://github.com/pandas-dev/pandas/issues/47172
|
| 1318 |
+
|
| 1319 |
+
labels = [f"c{i}" for i in range(10)]
|
| 1320 |
+
df = DataFrame({col: np.zeros(len(labels)) for col in labels}, index=labels)
|
| 1321 |
+
values = df._mgr.blocks[0].values
|
| 1322 |
+
|
| 1323 |
+
with tm.raises_chained_assignment_error():
|
| 1324 |
+
for label in df.columns:
|
| 1325 |
+
df[label][label] = 1
|
| 1326 |
+
if not using_copy_on_write:
|
| 1327 |
+
# diagonal values all updated
|
| 1328 |
+
assert np.all(values[np.arange(10), np.arange(10)] == 1)
|
| 1329 |
+
else:
|
| 1330 |
+
# original dataframe not updated
|
| 1331 |
+
assert np.all(values[np.arange(10), np.arange(10)] == 0)
|
| 1332 |
+
|
| 1333 |
+
def test_setitem_column_frame_as_category(self):
|
| 1334 |
+
# GH31581
|
| 1335 |
+
df = DataFrame([1, 2, 3])
|
| 1336 |
+
df["col1"] = DataFrame([1, 2, 3], dtype="category")
|
| 1337 |
+
df["col2"] = Series([1, 2, 3], dtype="category")
|
| 1338 |
+
|
| 1339 |
+
expected_types = Series(
|
| 1340 |
+
["int64", "category", "category"], index=[0, "col1", "col2"], dtype=object
|
| 1341 |
+
)
|
| 1342 |
+
tm.assert_series_equal(df.dtypes, expected_types)
|
| 1343 |
+
|
| 1344 |
+
@pytest.mark.parametrize("dtype", ["int64", "Int64"])
|
| 1345 |
+
def test_setitem_iloc_with_numpy_array(self, dtype):
|
| 1346 |
+
# GH-33828
|
| 1347 |
+
df = DataFrame({"a": np.ones(3)}, dtype=dtype)
|
| 1348 |
+
df.iloc[np.array([0]), np.array([0])] = np.array([[2]])
|
| 1349 |
+
|
| 1350 |
+
expected = DataFrame({"a": [2, 1, 1]}, dtype=dtype)
|
| 1351 |
+
tm.assert_frame_equal(df, expected)
|
| 1352 |
+
|
| 1353 |
+
def test_setitem_frame_dup_cols_dtype(self):
|
| 1354 |
+
# GH#53143
|
| 1355 |
+
df = DataFrame([[1, 2, 3, 4], [4, 5, 6, 7]], columns=["a", "b", "a", "c"])
|
| 1356 |
+
rhs = DataFrame([[0, 1.5], [2, 2.5]], columns=["a", "a"])
|
| 1357 |
+
df["a"] = rhs
|
| 1358 |
+
expected = DataFrame(
|
| 1359 |
+
[[0, 2, 1.5, 4], [2, 5, 2.5, 7]], columns=["a", "b", "a", "c"]
|
| 1360 |
+
)
|
| 1361 |
+
tm.assert_frame_equal(df, expected)
|
| 1362 |
+
|
| 1363 |
+
df = DataFrame([[1, 2, 3], [4, 5, 6]], columns=["a", "a", "b"])
|
| 1364 |
+
rhs = DataFrame([[0, 1.5], [2, 2.5]], columns=["a", "a"])
|
| 1365 |
+
df["a"] = rhs
|
| 1366 |
+
expected = DataFrame([[0, 1.5, 3], [2, 2.5, 6]], columns=["a", "a", "b"])
|
| 1367 |
+
tm.assert_frame_equal(df, expected)
|
| 1368 |
+
|
| 1369 |
+
def test_frame_setitem_empty_dataframe(self):
|
| 1370 |
+
# GH#28871
|
| 1371 |
+
dti = DatetimeIndex(["2000-01-01"], dtype="M8[ns]", name="date")
|
| 1372 |
+
df = DataFrame({"date": dti}).set_index("date")
|
| 1373 |
+
df = df[0:0].copy()
|
| 1374 |
+
|
| 1375 |
+
df["3010"] = None
|
| 1376 |
+
df["2010"] = None
|
| 1377 |
+
|
| 1378 |
+
expected = DataFrame(
|
| 1379 |
+
[],
|
| 1380 |
+
columns=["3010", "2010"],
|
| 1381 |
+
index=dti[:0],
|
| 1382 |
+
)
|
| 1383 |
+
tm.assert_frame_equal(df, expected)
|
| 1384 |
+
|
| 1385 |
+
|
| 1386 |
+
def test_full_setter_loc_incompatible_dtype():
|
| 1387 |
+
# https://github.com/pandas-dev/pandas/issues/55791
|
| 1388 |
+
df = DataFrame({"a": [1, 2]})
|
| 1389 |
+
with tm.assert_produces_warning(FutureWarning, match="incompatible dtype"):
|
| 1390 |
+
df.loc[:, "a"] = True
|
| 1391 |
+
expected = DataFrame({"a": [True, True]})
|
| 1392 |
+
tm.assert_frame_equal(df, expected)
|
| 1393 |
+
|
| 1394 |
+
df = DataFrame({"a": [1, 2]})
|
| 1395 |
+
with tm.assert_produces_warning(FutureWarning, match="incompatible dtype"):
|
| 1396 |
+
df.loc[:, "a"] = {0: 3.5, 1: 4.5}
|
| 1397 |
+
expected = DataFrame({"a": [3.5, 4.5]})
|
| 1398 |
+
tm.assert_frame_equal(df, expected)
|
| 1399 |
+
|
| 1400 |
+
df = DataFrame({"a": [1, 2]})
|
| 1401 |
+
df.loc[:, "a"] = {0: 3, 1: 4}
|
| 1402 |
+
expected = DataFrame({"a": [3, 4]})
|
| 1403 |
+
tm.assert_frame_equal(df, expected)
|
| 1404 |
+
|
| 1405 |
+
|
| 1406 |
+
def test_setitem_partial_row_multiple_columns():
|
| 1407 |
+
# https://github.com/pandas-dev/pandas/issues/56503
|
| 1408 |
+
df = DataFrame({"A": [1, 2, 3], "B": [4.0, 5, 6]})
|
| 1409 |
+
# should not warn
|
| 1410 |
+
df.loc[df.index <= 1, ["F", "G"]] = (1, "abc")
|
| 1411 |
+
expected = DataFrame(
|
| 1412 |
+
{
|
| 1413 |
+
"A": [1, 2, 3],
|
| 1414 |
+
"B": [4.0, 5, 6],
|
| 1415 |
+
"F": [1.0, 1, float("nan")],
|
| 1416 |
+
"G": ["abc", "abc", float("nan")],
|
| 1417 |
+
}
|
| 1418 |
+
)
|
| 1419 |
+
tm.assert_frame_equal(df, expected)
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/test_take.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
|
| 3 |
+
import pandas._testing as tm
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class TestDataFrameTake:
|
| 7 |
+
def test_take_slices_deprecated(self, float_frame):
|
| 8 |
+
# GH#51539
|
| 9 |
+
df = float_frame
|
| 10 |
+
|
| 11 |
+
slc = slice(0, 4, 1)
|
| 12 |
+
with tm.assert_produces_warning(FutureWarning):
|
| 13 |
+
df.take(slc, axis=0)
|
| 14 |
+
with tm.assert_produces_warning(FutureWarning):
|
| 15 |
+
df.take(slc, axis=1)
|
| 16 |
+
|
| 17 |
+
def test_take(self, float_frame):
|
| 18 |
+
# homogeneous
|
| 19 |
+
order = [3, 1, 2, 0]
|
| 20 |
+
for df in [float_frame]:
|
| 21 |
+
result = df.take(order, axis=0)
|
| 22 |
+
expected = df.reindex(df.index.take(order))
|
| 23 |
+
tm.assert_frame_equal(result, expected)
|
| 24 |
+
|
| 25 |
+
# axis = 1
|
| 26 |
+
result = df.take(order, axis=1)
|
| 27 |
+
expected = df.loc[:, ["D", "B", "C", "A"]]
|
| 28 |
+
tm.assert_frame_equal(result, expected, check_names=False)
|
| 29 |
+
|
| 30 |
+
# negative indices
|
| 31 |
+
order = [2, 1, -1]
|
| 32 |
+
for df in [float_frame]:
|
| 33 |
+
result = df.take(order, axis=0)
|
| 34 |
+
expected = df.reindex(df.index.take(order))
|
| 35 |
+
tm.assert_frame_equal(result, expected)
|
| 36 |
+
|
| 37 |
+
result = df.take(order, axis=0)
|
| 38 |
+
tm.assert_frame_equal(result, expected)
|
| 39 |
+
|
| 40 |
+
# axis = 1
|
| 41 |
+
result = df.take(order, axis=1)
|
| 42 |
+
expected = df.loc[:, ["C", "B", "D"]]
|
| 43 |
+
tm.assert_frame_equal(result, expected, check_names=False)
|
| 44 |
+
|
| 45 |
+
# illegal indices
|
| 46 |
+
msg = "indices are out-of-bounds"
|
| 47 |
+
with pytest.raises(IndexError, match=msg):
|
| 48 |
+
df.take([3, 1, 2, 30], axis=0)
|
| 49 |
+
with pytest.raises(IndexError, match=msg):
|
| 50 |
+
df.take([3, 1, 2, -31], axis=0)
|
| 51 |
+
with pytest.raises(IndexError, match=msg):
|
| 52 |
+
df.take([3, 1, 2, 5], axis=1)
|
| 53 |
+
with pytest.raises(IndexError, match=msg):
|
| 54 |
+
df.take([3, 1, 2, -5], axis=1)
|
| 55 |
+
|
| 56 |
+
def test_take_mixed_type(self, float_string_frame):
|
| 57 |
+
# mixed-dtype
|
| 58 |
+
order = [4, 1, 2, 0, 3]
|
| 59 |
+
for df in [float_string_frame]:
|
| 60 |
+
result = df.take(order, axis=0)
|
| 61 |
+
expected = df.reindex(df.index.take(order))
|
| 62 |
+
tm.assert_frame_equal(result, expected)
|
| 63 |
+
|
| 64 |
+
# axis = 1
|
| 65 |
+
result = df.take(order, axis=1)
|
| 66 |
+
expected = df.loc[:, ["foo", "B", "C", "A", "D"]]
|
| 67 |
+
tm.assert_frame_equal(result, expected)
|
| 68 |
+
|
| 69 |
+
# negative indices
|
| 70 |
+
order = [4, 1, -2]
|
| 71 |
+
for df in [float_string_frame]:
|
| 72 |
+
result = df.take(order, axis=0)
|
| 73 |
+
expected = df.reindex(df.index.take(order))
|
| 74 |
+
tm.assert_frame_equal(result, expected)
|
| 75 |
+
|
| 76 |
+
# axis = 1
|
| 77 |
+
result = df.take(order, axis=1)
|
| 78 |
+
expected = df.loc[:, ["foo", "B", "D"]]
|
| 79 |
+
tm.assert_frame_equal(result, expected)
|
| 80 |
+
|
| 81 |
+
def test_take_mixed_numeric(self, mixed_float_frame, mixed_int_frame):
|
| 82 |
+
# by dtype
|
| 83 |
+
order = [1, 2, 0, 3]
|
| 84 |
+
for df in [mixed_float_frame, mixed_int_frame]:
|
| 85 |
+
result = df.take(order, axis=0)
|
| 86 |
+
expected = df.reindex(df.index.take(order))
|
| 87 |
+
tm.assert_frame_equal(result, expected)
|
| 88 |
+
|
| 89 |
+
# axis = 1
|
| 90 |
+
result = df.take(order, axis=1)
|
| 91 |
+
expected = df.loc[:, ["B", "C", "A", "D"]]
|
| 92 |
+
tm.assert_frame_equal(result, expected)
|
lib/python3.12/site-packages/pandas/tests/frame/indexing/test_where.py
ADDED
|
@@ -0,0 +1,1099 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from datetime import datetime
|
| 2 |
+
|
| 3 |
+
from hypothesis import given
|
| 4 |
+
import numpy as np
|
| 5 |
+
import pytest
|
| 6 |
+
|
| 7 |
+
from pandas.core.dtypes.common import is_scalar
|
| 8 |
+
|
| 9 |
+
import pandas as pd
|
| 10 |
+
from pandas import (
|
| 11 |
+
DataFrame,
|
| 12 |
+
DatetimeIndex,
|
| 13 |
+
Index,
|
| 14 |
+
Series,
|
| 15 |
+
StringDtype,
|
| 16 |
+
Timestamp,
|
| 17 |
+
date_range,
|
| 18 |
+
isna,
|
| 19 |
+
)
|
| 20 |
+
import pandas._testing as tm
|
| 21 |
+
from pandas._testing._hypothesis import OPTIONAL_ONE_OF_ALL
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
@pytest.fixture(params=["default", "float_string", "mixed_float", "mixed_int"])
|
| 25 |
+
def where_frame(request, float_string_frame, mixed_float_frame, mixed_int_frame):
|
| 26 |
+
if request.param == "default":
|
| 27 |
+
return DataFrame(
|
| 28 |
+
np.random.default_rng(2).standard_normal((5, 3)), columns=["A", "B", "C"]
|
| 29 |
+
)
|
| 30 |
+
if request.param == "float_string":
|
| 31 |
+
return float_string_frame
|
| 32 |
+
if request.param == "mixed_float":
|
| 33 |
+
return mixed_float_frame
|
| 34 |
+
if request.param == "mixed_int":
|
| 35 |
+
return mixed_int_frame
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def _safe_add(df):
|
| 39 |
+
# only add to the numeric items
|
| 40 |
+
def is_ok(s):
|
| 41 |
+
return (
|
| 42 |
+
issubclass(s.dtype.type, (np.integer, np.floating)) and s.dtype != "uint8"
|
| 43 |
+
)
|
| 44 |
+
|
| 45 |
+
return DataFrame(dict((c, s + 1) if is_ok(s) else (c, s) for c, s in df.items()))
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
class TestDataFrameIndexingWhere:
|
| 49 |
+
def test_where_get(self, where_frame, float_string_frame):
|
| 50 |
+
def _check_get(df, cond, check_dtypes=True):
|
| 51 |
+
other1 = _safe_add(df)
|
| 52 |
+
rs = df.where(cond, other1)
|
| 53 |
+
rs2 = df.where(cond.values, other1)
|
| 54 |
+
for k, v in rs.items():
|
| 55 |
+
exp = Series(np.where(cond[k], df[k], other1[k]), index=v.index)
|
| 56 |
+
tm.assert_series_equal(v, exp, check_names=False)
|
| 57 |
+
tm.assert_frame_equal(rs, rs2)
|
| 58 |
+
|
| 59 |
+
# dtypes
|
| 60 |
+
if check_dtypes:
|
| 61 |
+
assert (rs.dtypes == df.dtypes).all()
|
| 62 |
+
|
| 63 |
+
# check getting
|
| 64 |
+
df = where_frame
|
| 65 |
+
if df is float_string_frame:
|
| 66 |
+
msg = "'>' not supported between instances of 'str' and 'int'"
|
| 67 |
+
with pytest.raises(TypeError, match=msg):
|
| 68 |
+
df > 0
|
| 69 |
+
return
|
| 70 |
+
cond = df > 0
|
| 71 |
+
_check_get(df, cond)
|
| 72 |
+
|
| 73 |
+
def test_where_upcasting(self):
|
| 74 |
+
# upcasting case (GH # 2794)
|
| 75 |
+
df = DataFrame(
|
| 76 |
+
{
|
| 77 |
+
c: Series([1] * 3, dtype=c)
|
| 78 |
+
for c in ["float32", "float64", "int32", "int64"]
|
| 79 |
+
}
|
| 80 |
+
)
|
| 81 |
+
df.iloc[1, :] = 0
|
| 82 |
+
result = df.dtypes
|
| 83 |
+
expected = Series(
|
| 84 |
+
[
|
| 85 |
+
np.dtype("float32"),
|
| 86 |
+
np.dtype("float64"),
|
| 87 |
+
np.dtype("int32"),
|
| 88 |
+
np.dtype("int64"),
|
| 89 |
+
],
|
| 90 |
+
index=["float32", "float64", "int32", "int64"],
|
| 91 |
+
)
|
| 92 |
+
|
| 93 |
+
# when we don't preserve boolean casts
|
| 94 |
+
#
|
| 95 |
+
# expected = Series({ 'float32' : 1, 'float64' : 3 })
|
| 96 |
+
|
| 97 |
+
tm.assert_series_equal(result, expected)
|
| 98 |
+
|
| 99 |
+
@pytest.mark.filterwarnings("ignore:Downcasting object dtype arrays:FutureWarning")
|
| 100 |
+
def test_where_alignment(self, where_frame, float_string_frame):
|
| 101 |
+
# aligning
|
| 102 |
+
def _check_align(df, cond, other, check_dtypes=True):
|
| 103 |
+
rs = df.where(cond, other)
|
| 104 |
+
for i, k in enumerate(rs.columns):
|
| 105 |
+
result = rs[k]
|
| 106 |
+
d = df[k].values
|
| 107 |
+
c = cond[k].reindex(df[k].index).fillna(False).values
|
| 108 |
+
|
| 109 |
+
if is_scalar(other):
|
| 110 |
+
o = other
|
| 111 |
+
elif isinstance(other, np.ndarray):
|
| 112 |
+
o = Series(other[:, i], index=result.index).values
|
| 113 |
+
else:
|
| 114 |
+
o = other[k].values
|
| 115 |
+
|
| 116 |
+
new_values = d if c.all() else np.where(c, d, o)
|
| 117 |
+
expected = Series(new_values, index=result.index, name=k)
|
| 118 |
+
|
| 119 |
+
# since we can't always have the correct numpy dtype
|
| 120 |
+
# as numpy doesn't know how to downcast, don't check
|
| 121 |
+
tm.assert_series_equal(result, expected, check_dtype=False)
|
| 122 |
+
|
| 123 |
+
# dtypes
|
| 124 |
+
# can't check dtype when other is an ndarray
|
| 125 |
+
|
| 126 |
+
if check_dtypes and not isinstance(other, np.ndarray):
|
| 127 |
+
assert (rs.dtypes == df.dtypes).all()
|
| 128 |
+
|
| 129 |
+
df = where_frame
|
| 130 |
+
if df is float_string_frame:
|
| 131 |
+
msg = "'>' not supported between instances of 'str' and 'int'"
|
| 132 |
+
with pytest.raises(TypeError, match=msg):
|
| 133 |
+
df > 0
|
| 134 |
+
return
|
| 135 |
+
|
| 136 |
+
# other is a frame
|
| 137 |
+
cond = (df > 0)[1:]
|
| 138 |
+
_check_align(df, cond, _safe_add(df))
|
| 139 |
+
|
| 140 |
+
# check other is ndarray
|
| 141 |
+
cond = df > 0
|
| 142 |
+
_check_align(df, cond, (_safe_add(df).values))
|
| 143 |
+
|
| 144 |
+
# integers are upcast, so don't check the dtypes
|
| 145 |
+
cond = df > 0
|
| 146 |
+
check_dtypes = all(not issubclass(s.type, np.integer) for s in df.dtypes)
|
| 147 |
+
_check_align(df, cond, np.nan, check_dtypes=check_dtypes)
|
| 148 |
+
|
| 149 |
+
# Ignore deprecation warning in Python 3.12 for inverting a bool
|
| 150 |
+
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
|
| 151 |
+
def test_where_invalid(self):
|
| 152 |
+
# invalid conditions
|
| 153 |
+
df = DataFrame(
|
| 154 |
+
np.random.default_rng(2).standard_normal((5, 3)), columns=["A", "B", "C"]
|
| 155 |
+
)
|
| 156 |
+
cond = df > 0
|
| 157 |
+
|
| 158 |
+
err1 = (df + 1).values[0:2, :]
|
| 159 |
+
msg = "other must be the same shape as self when an ndarray"
|
| 160 |
+
with pytest.raises(ValueError, match=msg):
|
| 161 |
+
df.where(cond, err1)
|
| 162 |
+
|
| 163 |
+
err2 = cond.iloc[:2, :].values
|
| 164 |
+
other1 = _safe_add(df)
|
| 165 |
+
msg = "Array conditional must be same shape as self"
|
| 166 |
+
with pytest.raises(ValueError, match=msg):
|
| 167 |
+
df.where(err2, other1)
|
| 168 |
+
|
| 169 |
+
with pytest.raises(ValueError, match=msg):
|
| 170 |
+
df.mask(True)
|
| 171 |
+
with pytest.raises(ValueError, match=msg):
|
| 172 |
+
df.mask(0)
|
| 173 |
+
|
| 174 |
+
@pytest.mark.filterwarnings("ignore:Downcasting object dtype arrays:FutureWarning")
|
| 175 |
+
def test_where_set(self, where_frame, float_string_frame, mixed_int_frame):
|
| 176 |
+
# where inplace
|
| 177 |
+
|
| 178 |
+
def _check_set(df, cond, check_dtypes=True):
|
| 179 |
+
dfi = df.copy()
|
| 180 |
+
econd = cond.reindex_like(df).fillna(True).infer_objects(copy=False)
|
| 181 |
+
expected = dfi.mask(~econd)
|
| 182 |
+
|
| 183 |
+
return_value = dfi.where(cond, np.nan, inplace=True)
|
| 184 |
+
assert return_value is None
|
| 185 |
+
tm.assert_frame_equal(dfi, expected)
|
| 186 |
+
|
| 187 |
+
# dtypes (and confirm upcasts)x
|
| 188 |
+
if check_dtypes:
|
| 189 |
+
for k, v in df.dtypes.items():
|
| 190 |
+
if issubclass(v.type, np.integer) and not cond[k].all():
|
| 191 |
+
v = np.dtype("float64")
|
| 192 |
+
assert dfi[k].dtype == v
|
| 193 |
+
|
| 194 |
+
df = where_frame
|
| 195 |
+
if df is float_string_frame:
|
| 196 |
+
msg = "'>' not supported between instances of 'str' and 'int'"
|
| 197 |
+
with pytest.raises(TypeError, match=msg):
|
| 198 |
+
df > 0
|
| 199 |
+
return
|
| 200 |
+
if df is mixed_int_frame:
|
| 201 |
+
df = df.astype("float64")
|
| 202 |
+
|
| 203 |
+
cond = df > 0
|
| 204 |
+
_check_set(df, cond)
|
| 205 |
+
|
| 206 |
+
cond = df >= 0
|
| 207 |
+
_check_set(df, cond)
|
| 208 |
+
|
| 209 |
+
# aligning
|
| 210 |
+
cond = (df >= 0)[1:]
|
| 211 |
+
_check_set(df, cond)
|
| 212 |
+
|
| 213 |
+
def test_where_series_slicing(self):
|
| 214 |
+
# GH 10218
|
| 215 |
+
# test DataFrame.where with Series slicing
|
| 216 |
+
df = DataFrame({"a": range(3), "b": range(4, 7)})
|
| 217 |
+
result = df.where(df["a"] == 1)
|
| 218 |
+
expected = df[df["a"] == 1].reindex(df.index)
|
| 219 |
+
tm.assert_frame_equal(result, expected)
|
| 220 |
+
|
| 221 |
+
@pytest.mark.parametrize("klass", [list, tuple, np.array])
|
| 222 |
+
def test_where_array_like(self, klass):
|
| 223 |
+
# see gh-15414
|
| 224 |
+
df = DataFrame({"a": [1, 2, 3]})
|
| 225 |
+
cond = [[False], [True], [True]]
|
| 226 |
+
expected = DataFrame({"a": [np.nan, 2, 3]})
|
| 227 |
+
|
| 228 |
+
result = df.where(klass(cond))
|
| 229 |
+
tm.assert_frame_equal(result, expected)
|
| 230 |
+
|
| 231 |
+
df["b"] = 2
|
| 232 |
+
expected["b"] = [2, np.nan, 2]
|
| 233 |
+
cond = [[False, True], [True, False], [True, True]]
|
| 234 |
+
|
| 235 |
+
result = df.where(klass(cond))
|
| 236 |
+
tm.assert_frame_equal(result, expected)
|
| 237 |
+
|
| 238 |
+
@pytest.mark.parametrize(
|
| 239 |
+
"cond",
|
| 240 |
+
[
|
| 241 |
+
[[1], [0], [1]],
|
| 242 |
+
Series([[2], [5], [7]]),
|
| 243 |
+
DataFrame({"a": [2, 5, 7]}),
|
| 244 |
+
[["True"], ["False"], ["True"]],
|
| 245 |
+
[[Timestamp("2017-01-01")], [pd.NaT], [Timestamp("2017-01-02")]],
|
| 246 |
+
],
|
| 247 |
+
)
|
| 248 |
+
def test_where_invalid_input_single(self, cond):
|
| 249 |
+
# see gh-15414: only boolean arrays accepted
|
| 250 |
+
df = DataFrame({"a": [1, 2, 3]})
|
| 251 |
+
msg = "Boolean array expected for the condition"
|
| 252 |
+
|
| 253 |
+
with pytest.raises(ValueError, match=msg):
|
| 254 |
+
df.where(cond)
|
| 255 |
+
|
| 256 |
+
@pytest.mark.parametrize(
|
| 257 |
+
"cond",
|
| 258 |
+
[
|
| 259 |
+
[[0, 1], [1, 0], [1, 1]],
|
| 260 |
+
Series([[0, 2], [5, 0], [4, 7]]),
|
| 261 |
+
[["False", "True"], ["True", "False"], ["True", "True"]],
|
| 262 |
+
DataFrame({"a": [2, 5, 7], "b": [4, 8, 9]}),
|
| 263 |
+
[
|
| 264 |
+
[pd.NaT, Timestamp("2017-01-01")],
|
| 265 |
+
[Timestamp("2017-01-02"), pd.NaT],
|
| 266 |
+
[Timestamp("2017-01-03"), Timestamp("2017-01-03")],
|
| 267 |
+
],
|
| 268 |
+
],
|
| 269 |
+
)
|
| 270 |
+
def test_where_invalid_input_multiple(self, cond):
|
| 271 |
+
# see gh-15414: only boolean arrays accepted
|
| 272 |
+
df = DataFrame({"a": [1, 2, 3], "b": [2, 2, 2]})
|
| 273 |
+
msg = "Boolean array expected for the condition"
|
| 274 |
+
|
| 275 |
+
with pytest.raises(ValueError, match=msg):
|
| 276 |
+
df.where(cond)
|
| 277 |
+
|
| 278 |
+
def test_where_dataframe_col_match(self):
|
| 279 |
+
df = DataFrame([[1, 2, 3], [4, 5, 6]])
|
| 280 |
+
cond = DataFrame([[True, False, True], [False, False, True]])
|
| 281 |
+
|
| 282 |
+
result = df.where(cond)
|
| 283 |
+
expected = DataFrame([[1.0, np.nan, 3], [np.nan, np.nan, 6]])
|
| 284 |
+
tm.assert_frame_equal(result, expected)
|
| 285 |
+
|
| 286 |
+
# this *does* align, though has no matching columns
|
| 287 |
+
cond.columns = ["a", "b", "c"]
|
| 288 |
+
result = df.where(cond)
|
| 289 |
+
expected = DataFrame(np.nan, index=df.index, columns=df.columns)
|
| 290 |
+
tm.assert_frame_equal(result, expected)
|
| 291 |
+
|
| 292 |
+
def test_where_ndframe_align(self):
|
| 293 |
+
msg = "Array conditional must be same shape as self"
|
| 294 |
+
df = DataFrame([[1, 2, 3], [4, 5, 6]])
|
| 295 |
+
|
| 296 |
+
cond = [True]
|
| 297 |
+
with pytest.raises(ValueError, match=msg):
|
| 298 |
+
df.where(cond)
|
| 299 |
+
|
| 300 |
+
expected = DataFrame([[1, 2, 3], [np.nan, np.nan, np.nan]])
|
| 301 |
+
|
| 302 |
+
out = df.where(Series(cond))
|
| 303 |
+
tm.assert_frame_equal(out, expected)
|
| 304 |
+
|
| 305 |
+
cond = np.array([False, True, False, True])
|
| 306 |
+
with pytest.raises(ValueError, match=msg):
|
| 307 |
+
df.where(cond)
|
| 308 |
+
|
| 309 |
+
expected = DataFrame([[np.nan, np.nan, np.nan], [4, 5, 6]])
|
| 310 |
+
|
| 311 |
+
out = df.where(Series(cond))
|
| 312 |
+
tm.assert_frame_equal(out, expected)
|
| 313 |
+
|
| 314 |
+
def test_where_bug(self):
|
| 315 |
+
# see gh-2793
|
| 316 |
+
df = DataFrame(
|
| 317 |
+
{"a": [1.0, 2.0, 3.0, 4.0], "b": [4.0, 3.0, 2.0, 1.0]}, dtype="float64"
|
| 318 |
+
)
|
| 319 |
+
expected = DataFrame(
|
| 320 |
+
{"a": [np.nan, np.nan, 3.0, 4.0], "b": [4.0, 3.0, np.nan, np.nan]},
|
| 321 |
+
dtype="float64",
|
| 322 |
+
)
|
| 323 |
+
result = df.where(df > 2, np.nan)
|
| 324 |
+
tm.assert_frame_equal(result, expected)
|
| 325 |
+
|
| 326 |
+
result = df.copy()
|
| 327 |
+
return_value = result.where(result > 2, np.nan, inplace=True)
|
| 328 |
+
assert return_value is None
|
| 329 |
+
tm.assert_frame_equal(result, expected)
|
| 330 |
+
|
| 331 |
+
def test_where_bug_mixed(self, any_signed_int_numpy_dtype):
|
| 332 |
+
# see gh-2793
|
| 333 |
+
df = DataFrame(
|
| 334 |
+
{
|
| 335 |
+
"a": np.array([1, 2, 3, 4], dtype=any_signed_int_numpy_dtype),
|
| 336 |
+
"b": np.array([4.0, 3.0, 2.0, 1.0], dtype="float64"),
|
| 337 |
+
}
|
| 338 |
+
)
|
| 339 |
+
|
| 340 |
+
expected = DataFrame(
|
| 341 |
+
{"a": [-1, -1, 3, 4], "b": [4.0, 3.0, -1, -1]},
|
| 342 |
+
).astype({"a": any_signed_int_numpy_dtype, "b": "float64"})
|
| 343 |
+
|
| 344 |
+
result = df.where(df > 2, -1)
|
| 345 |
+
tm.assert_frame_equal(result, expected)
|
| 346 |
+
|
| 347 |
+
result = df.copy()
|
| 348 |
+
return_value = result.where(result > 2, -1, inplace=True)
|
| 349 |
+
assert return_value is None
|
| 350 |
+
tm.assert_frame_equal(result, expected)
|
| 351 |
+
|
| 352 |
+
def test_where_bug_transposition(self):
|
| 353 |
+
# see gh-7506
|
| 354 |
+
a = DataFrame({0: [1, 2], 1: [3, 4], 2: [5, 6]})
|
| 355 |
+
b = DataFrame({0: [np.nan, 8], 1: [9, np.nan], 2: [np.nan, np.nan]})
|
| 356 |
+
do_not_replace = b.isna() | (a > b)
|
| 357 |
+
|
| 358 |
+
expected = a.copy()
|
| 359 |
+
expected[~do_not_replace] = b
|
| 360 |
+
|
| 361 |
+
msg = "Downcasting behavior in Series and DataFrame methods 'where'"
|
| 362 |
+
with tm.assert_produces_warning(FutureWarning, match=msg):
|
| 363 |
+
result = a.where(do_not_replace, b)
|
| 364 |
+
tm.assert_frame_equal(result, expected)
|
| 365 |
+
|
| 366 |
+
a = DataFrame({0: [4, 6], 1: [1, 0]})
|
| 367 |
+
b = DataFrame({0: [np.nan, 3], 1: [3, np.nan]})
|
| 368 |
+
do_not_replace = b.isna() | (a > b)
|
| 369 |
+
|
| 370 |
+
expected = a.copy()
|
| 371 |
+
expected[~do_not_replace] = b
|
| 372 |
+
|
| 373 |
+
with tm.assert_produces_warning(FutureWarning, match=msg):
|
| 374 |
+
result = a.where(do_not_replace, b)
|
| 375 |
+
tm.assert_frame_equal(result, expected)
|
| 376 |
+
|
| 377 |
+
def test_where_datetime(self):
|
| 378 |
+
# GH 3311
|
| 379 |
+
df = DataFrame(
|
| 380 |
+
{
|
| 381 |
+
"A": date_range("20130102", periods=5),
|
| 382 |
+
"B": date_range("20130104", periods=5),
|
| 383 |
+
"C": np.random.default_rng(2).standard_normal(5),
|
| 384 |
+
}
|
| 385 |
+
)
|
| 386 |
+
|
| 387 |
+
stamp = datetime(2013, 1, 3)
|
| 388 |
+
msg = "'>' not supported between instances of 'float' and 'datetime.datetime'"
|
| 389 |
+
with pytest.raises(TypeError, match=msg):
|
| 390 |
+
df > stamp
|
| 391 |
+
|
| 392 |
+
result = df[df.iloc[:, :-1] > stamp]
|
| 393 |
+
|
| 394 |
+
expected = df.copy()
|
| 395 |
+
expected.loc[[0, 1], "A"] = np.nan
|
| 396 |
+
|
| 397 |
+
expected.loc[:, "C"] = np.nan
|
| 398 |
+
tm.assert_frame_equal(result, expected)
|
| 399 |
+
|
| 400 |
+
def test_where_none(self):
|
| 401 |
+
# GH 4667
|
| 402 |
+
# setting with None changes dtype
|
| 403 |
+
df = DataFrame({"series": Series(range(10))}).astype(float)
|
| 404 |
+
df[df > 7] = None
|
| 405 |
+
expected = DataFrame(
|
| 406 |
+
{"series": Series([0, 1, 2, 3, 4, 5, 6, 7, np.nan, np.nan])}
|
| 407 |
+
)
|
| 408 |
+
tm.assert_frame_equal(df, expected)
|
| 409 |
+
|
| 410 |
+
# GH 7656
|
| 411 |
+
df = DataFrame(
|
| 412 |
+
[
|
| 413 |
+
{"A": 1, "B": np.nan, "C": "Test"},
|
| 414 |
+
{"A": np.nan, "B": "Test", "C": np.nan},
|
| 415 |
+
]
|
| 416 |
+
)
|
| 417 |
+
|
| 418 |
+
orig = df.copy()
|
| 419 |
+
|
| 420 |
+
mask = ~isna(df)
|
| 421 |
+
df.where(mask, None, inplace=True)
|
| 422 |
+
expected = DataFrame(
|
| 423 |
+
{
|
| 424 |
+
"A": [1.0, np.nan],
|
| 425 |
+
"B": [None, "Test"],
|
| 426 |
+
"C": ["Test", None],
|
| 427 |
+
}
|
| 428 |
+
)
|
| 429 |
+
tm.assert_frame_equal(df, expected)
|
| 430 |
+
|
| 431 |
+
df = orig.copy()
|
| 432 |
+
df[~mask] = None
|
| 433 |
+
tm.assert_frame_equal(df, expected)
|
| 434 |
+
|
| 435 |
+
def test_where_empty_df_and_empty_cond_having_non_bool_dtypes(self):
|
| 436 |
+
# see gh-21947
|
| 437 |
+
df = DataFrame(columns=["a"])
|
| 438 |
+
cond = df
|
| 439 |
+
assert (cond.dtypes == object).all()
|
| 440 |
+
|
| 441 |
+
result = df.where(cond)
|
| 442 |
+
tm.assert_frame_equal(result, df)
|
| 443 |
+
|
| 444 |
+
def test_where_align(self):
|
| 445 |
+
def create():
|
| 446 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((10, 3)))
|
| 447 |
+
df.iloc[3:5, 0] = np.nan
|
| 448 |
+
df.iloc[4:6, 1] = np.nan
|
| 449 |
+
df.iloc[5:8, 2] = np.nan
|
| 450 |
+
return df
|
| 451 |
+
|
| 452 |
+
# series
|
| 453 |
+
df = create()
|
| 454 |
+
expected = df.fillna(df.mean())
|
| 455 |
+
result = df.where(pd.notna(df), df.mean(), axis="columns")
|
| 456 |
+
tm.assert_frame_equal(result, expected)
|
| 457 |
+
|
| 458 |
+
return_value = df.where(pd.notna(df), df.mean(), inplace=True, axis="columns")
|
| 459 |
+
assert return_value is None
|
| 460 |
+
tm.assert_frame_equal(df, expected)
|
| 461 |
+
|
| 462 |
+
df = create().fillna(0)
|
| 463 |
+
expected = df.apply(lambda x, y: x.where(x > 0, y), y=df[0])
|
| 464 |
+
result = df.where(df > 0, df[0], axis="index")
|
| 465 |
+
tm.assert_frame_equal(result, expected)
|
| 466 |
+
result = df.where(df > 0, df[0], axis="rows")
|
| 467 |
+
tm.assert_frame_equal(result, expected)
|
| 468 |
+
|
| 469 |
+
# frame
|
| 470 |
+
df = create()
|
| 471 |
+
expected = df.fillna(1)
|
| 472 |
+
result = df.where(
|
| 473 |
+
pd.notna(df), DataFrame(1, index=df.index, columns=df.columns)
|
| 474 |
+
)
|
| 475 |
+
tm.assert_frame_equal(result, expected)
|
| 476 |
+
|
| 477 |
+
def test_where_complex(self):
|
| 478 |
+
# GH 6345
|
| 479 |
+
expected = DataFrame([[1 + 1j, 2], [np.nan, 4 + 1j]], columns=["a", "b"])
|
| 480 |
+
df = DataFrame([[1 + 1j, 2], [5 + 1j, 4 + 1j]], columns=["a", "b"])
|
| 481 |
+
df[df.abs() >= 5] = np.nan
|
| 482 |
+
tm.assert_frame_equal(df, expected)
|
| 483 |
+
|
| 484 |
+
def test_where_axis(self):
|
| 485 |
+
# GH 9736
|
| 486 |
+
df = DataFrame(np.random.default_rng(2).standard_normal((2, 2)))
|
| 487 |
+
mask = DataFrame([[False, False], [False, False]])
|
| 488 |
+
ser = Series([0, 1])
|
| 489 |
+
|
| 490 |
+
expected = DataFrame([[0, 0], [1, 1]], dtype="float64")
|
| 491 |
+
result = df.where(mask, ser, axis="index")
|
| 492 |
+
tm.assert_frame_equal(result, expected)
|
| 493 |
+
|
| 494 |
+
result = df.copy()
|
| 495 |
+
return_value = result.where(mask, ser, axis="index", inplace=True)
|
| 496 |
+
assert return_value is None
|
| 497 |
+
tm.assert_frame_equal(result, expected)
|
| 498 |
+
|
| 499 |
+
expected = DataFrame([[0, 1], [0, 1]], dtype="float64")
|
| 500 |
+
result = df.where(mask, ser, axis="columns")
|
| 501 |
+
tm.assert_frame_equal(result, expected)
|
| 502 |
+
|
| 503 |
+
result = df.copy()
|
| 504 |
+
return_value = result.where(mask, ser, axis="columns", inplace=True)
|
| 505 |
+
assert return_value is None
|
| 506 |
+
tm.assert_frame_equal(result, expected)
|
| 507 |
+
|
| 508 |
+
def test_where_axis_with_upcast(self):
|
| 509 |
+
# Upcast needed
|
| 510 |
+
df = DataFrame([[1, 2], [3, 4]], dtype="int64")
|
| 511 |
+
mask = DataFrame([[False, False], [False, False]])
|
| 512 |
+
ser = Series([0, np.nan])
|
| 513 |
+
|
| 514 |
+
expected = DataFrame([[0, 0], [np.nan, np.nan]], dtype="float64")
|
| 515 |
+
result = df.where(mask, ser, axis="index")
|
| 516 |
+
tm.assert_frame_equal(result, expected)
|
| 517 |
+
|
| 518 |
+
result = df.copy()
|
| 519 |
+
with tm.assert_produces_warning(FutureWarning, match="incompatible dtype"):
|
| 520 |
+
return_value = result.where(mask, ser, axis="index", inplace=True)
|
| 521 |
+
assert return_value is None
|
| 522 |
+
tm.assert_frame_equal(result, expected)
|
| 523 |
+
|
| 524 |
+
expected = DataFrame([[0, np.nan], [0, np.nan]])
|
| 525 |
+
result = df.where(mask, ser, axis="columns")
|
| 526 |
+
tm.assert_frame_equal(result, expected)
|
| 527 |
+
|
| 528 |
+
expected = DataFrame(
|
| 529 |
+
{
|
| 530 |
+
0: np.array([0, 0], dtype="int64"),
|
| 531 |
+
1: np.array([np.nan, np.nan], dtype="float64"),
|
| 532 |
+
}
|
| 533 |
+
)
|
| 534 |
+
result = df.copy()
|
| 535 |
+
with tm.assert_produces_warning(FutureWarning, match="incompatible dtype"):
|
| 536 |
+
return_value = result.where(mask, ser, axis="columns", inplace=True)
|
| 537 |
+
assert return_value is None
|
| 538 |
+
tm.assert_frame_equal(result, expected)
|
| 539 |
+
|
| 540 |
+
def test_where_axis_multiple_dtypes(self):
|
| 541 |
+
# Multiple dtypes (=> multiple Blocks)
|
| 542 |
+
df = pd.concat(
|
| 543 |
+
[
|
| 544 |
+
DataFrame(np.random.default_rng(2).standard_normal((10, 2))),
|
| 545 |
+
DataFrame(
|
| 546 |
+
np.random.default_rng(2).integers(0, 10, size=(10, 2)),
|
| 547 |
+
dtype="int64",
|
| 548 |
+
),
|
| 549 |
+
],
|
| 550 |
+
ignore_index=True,
|
| 551 |
+
axis=1,
|
| 552 |
+
)
|
| 553 |
+
mask = DataFrame(False, columns=df.columns, index=df.index)
|
| 554 |
+
s1 = Series(1, index=df.columns)
|
| 555 |
+
s2 = Series(2, index=df.index)
|
| 556 |
+
|
| 557 |
+
result = df.where(mask, s1, axis="columns")
|
| 558 |
+
expected = DataFrame(1.0, columns=df.columns, index=df.index)
|
| 559 |
+
expected[2] = expected[2].astype("int64")
|
| 560 |
+
expected[3] = expected[3].astype("int64")
|
| 561 |
+
tm.assert_frame_equal(result, expected)
|
| 562 |
+
|
| 563 |
+
result = df.copy()
|
| 564 |
+
return_value = result.where(mask, s1, axis="columns", inplace=True)
|
| 565 |
+
assert return_value is None
|
| 566 |
+
tm.assert_frame_equal(result, expected)
|
| 567 |
+
|
| 568 |
+
result = df.where(mask, s2, axis="index")
|
| 569 |
+
expected = DataFrame(2.0, columns=df.columns, index=df.index)
|
| 570 |
+
expected[2] = expected[2].astype("int64")
|
| 571 |
+
expected[3] = expected[3].astype("int64")
|
| 572 |
+
tm.assert_frame_equal(result, expected)
|
| 573 |
+
|
| 574 |
+
result = df.copy()
|
| 575 |
+
return_value = result.where(mask, s2, axis="index", inplace=True)
|
| 576 |
+
assert return_value is None
|
| 577 |
+
tm.assert_frame_equal(result, expected)
|
| 578 |
+
|
| 579 |
+
# DataFrame vs DataFrame
|
| 580 |
+
d1 = df.copy().drop(1, axis=0)
|
| 581 |
+
# Explicit cast to avoid implicit cast when setting value to np.nan
|
| 582 |
+
expected = df.copy().astype("float")
|
| 583 |
+
expected.loc[1, :] = np.nan
|
| 584 |
+
|
| 585 |
+
result = df.where(mask, d1)
|
| 586 |
+
tm.assert_frame_equal(result, expected)
|
| 587 |
+
result = df.where(mask, d1, axis="index")
|
| 588 |
+
tm.assert_frame_equal(result, expected)
|
| 589 |
+
result = df.copy()
|
| 590 |
+
with tm.assert_produces_warning(FutureWarning, match="incompatible dtype"):
|
| 591 |
+
return_value = result.where(mask, d1, inplace=True)
|
| 592 |
+
assert return_value is None
|
| 593 |
+
tm.assert_frame_equal(result, expected)
|
| 594 |
+
result = df.copy()
|
| 595 |
+
with tm.assert_produces_warning(FutureWarning, match="incompatible dtype"):
|
| 596 |
+
return_value = result.where(mask, d1, inplace=True, axis="index")
|
| 597 |
+
assert return_value is None
|
| 598 |
+
tm.assert_frame_equal(result, expected)
|
| 599 |
+
|
| 600 |
+
d2 = df.copy().drop(1, axis=1)
|
| 601 |
+
expected = df.copy()
|
| 602 |
+
expected.loc[:, 1] = np.nan
|
| 603 |
+
|
| 604 |
+
result = df.where(mask, d2)
|
| 605 |
+
tm.assert_frame_equal(result, expected)
|
| 606 |
+
result = df.where(mask, d2, axis="columns")
|
| 607 |
+
tm.assert_frame_equal(result, expected)
|
| 608 |
+
result = df.copy()
|
| 609 |
+
return_value = result.where(mask, d2, inplace=True)
|
| 610 |
+
assert return_value is None
|
| 611 |
+
tm.assert_frame_equal(result, expected)
|
| 612 |
+
result = df.copy()
|
| 613 |
+
return_value = result.where(mask, d2, inplace=True, axis="columns")
|
| 614 |
+
assert return_value is None
|
| 615 |
+
tm.assert_frame_equal(result, expected)
|
| 616 |
+
|
| 617 |
+
def test_where_callable(self):
|
| 618 |
+
# GH 12533
|
| 619 |
+
df = DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
| 620 |
+
result = df.where(lambda x: x > 4, lambda x: x + 1)
|
| 621 |
+
exp = DataFrame([[2, 3, 4], [5, 5, 6], [7, 8, 9]])
|
| 622 |
+
tm.assert_frame_equal(result, exp)
|
| 623 |
+
tm.assert_frame_equal(result, df.where(df > 4, df + 1))
|
| 624 |
+
|
| 625 |
+
# return ndarray and scalar
|
| 626 |
+
result = df.where(lambda x: (x % 2 == 0).values, lambda x: 99)
|
| 627 |
+
exp = DataFrame([[99, 2, 99], [4, 99, 6], [99, 8, 99]])
|
| 628 |
+
tm.assert_frame_equal(result, exp)
|
| 629 |
+
tm.assert_frame_equal(result, df.where(df % 2 == 0, 99))
|
| 630 |
+
|
| 631 |
+
# chain
|
| 632 |
+
result = (df + 2).where(lambda x: x > 8, lambda x: x + 10)
|
| 633 |
+
exp = DataFrame([[13, 14, 15], [16, 17, 18], [9, 10, 11]])
|
| 634 |
+
tm.assert_frame_equal(result, exp)
|
| 635 |
+
tm.assert_frame_equal(result, (df + 2).where((df + 2) > 8, (df + 2) + 10))
|
| 636 |
+
|
| 637 |
+
def test_where_tz_values(self, tz_naive_fixture, frame_or_series):
|
| 638 |
+
obj1 = DataFrame(
|
| 639 |
+
DatetimeIndex(["20150101", "20150102", "20150103"], tz=tz_naive_fixture),
|
| 640 |
+
columns=["date"],
|
| 641 |
+
)
|
| 642 |
+
obj2 = DataFrame(
|
| 643 |
+
DatetimeIndex(["20150103", "20150104", "20150105"], tz=tz_naive_fixture),
|
| 644 |
+
columns=["date"],
|
| 645 |
+
)
|
| 646 |
+
mask = DataFrame([True, True, False], columns=["date"])
|
| 647 |
+
exp = DataFrame(
|
| 648 |
+
DatetimeIndex(["20150101", "20150102", "20150105"], tz=tz_naive_fixture),
|
| 649 |
+
columns=["date"],
|
| 650 |
+
)
|
| 651 |
+
if frame_or_series is Series:
|
| 652 |
+
obj1 = obj1["date"]
|
| 653 |
+
obj2 = obj2["date"]
|
| 654 |
+
mask = mask["date"]
|
| 655 |
+
exp = exp["date"]
|
| 656 |
+
|
| 657 |
+
result = obj1.where(mask, obj2)
|
| 658 |
+
tm.assert_equal(exp, result)
|
| 659 |
+
|
| 660 |
+
def test_df_where_change_dtype(self):
|
| 661 |
+
# GH#16979
|
| 662 |
+
df = DataFrame(np.arange(2 * 3).reshape(2, 3), columns=list("ABC"))
|
| 663 |
+
mask = np.array([[True, False, False], [False, False, True]])
|
| 664 |
+
|
| 665 |
+
result = df.where(mask)
|
| 666 |
+
expected = DataFrame(
|
| 667 |
+
[[0, np.nan, np.nan], [np.nan, np.nan, 5]], columns=list("ABC")
|
| 668 |
+
)
|
| 669 |
+
|
| 670 |
+
tm.assert_frame_equal(result, expected)
|
| 671 |
+
|
| 672 |
+
@pytest.mark.parametrize("kwargs", [{}, {"other": None}])
|
| 673 |
+
def test_df_where_with_category(self, kwargs):
|
| 674 |
+
# GH#16979
|
| 675 |
+
data = np.arange(2 * 3, dtype=np.int64).reshape(2, 3)
|
| 676 |
+
df = DataFrame(data, columns=list("ABC"))
|
| 677 |
+
mask = np.array([[True, False, False], [False, False, True]])
|
| 678 |
+
|
| 679 |
+
# change type to category
|
| 680 |
+
df.A = df.A.astype("category")
|
| 681 |
+
df.B = df.B.astype("category")
|
| 682 |
+
df.C = df.C.astype("category")
|
| 683 |
+
|
| 684 |
+
result = df.where(mask, **kwargs)
|
| 685 |
+
A = pd.Categorical([0, np.nan], categories=[0, 3])
|
| 686 |
+
B = pd.Categorical([np.nan, np.nan], categories=[1, 4])
|
| 687 |
+
C = pd.Categorical([np.nan, 5], categories=[2, 5])
|
| 688 |
+
expected = DataFrame({"A": A, "B": B, "C": C})
|
| 689 |
+
|
| 690 |
+
tm.assert_frame_equal(result, expected)
|
| 691 |
+
|
| 692 |
+
# Check Series.where while we're here
|
| 693 |
+
result = df.A.where(mask[:, 0], **kwargs)
|
| 694 |
+
expected = Series(A, name="A")
|
| 695 |
+
|
| 696 |
+
tm.assert_series_equal(result, expected)
|
| 697 |
+
|
| 698 |
+
def test_where_categorical_filtering(self):
|
| 699 |
+
# GH#22609 Verify filtering operations on DataFrames with categorical Series
|
| 700 |
+
df = DataFrame(data=[[0, 0], [1, 1]], columns=["a", "b"])
|
| 701 |
+
df["b"] = df["b"].astype("category")
|
| 702 |
+
|
| 703 |
+
result = df.where(df["a"] > 0)
|
| 704 |
+
# Explicitly cast to 'float' to avoid implicit cast when setting np.nan
|
| 705 |
+
expected = df.copy().astype({"a": "float"})
|
| 706 |
+
expected.loc[0, :] = np.nan
|
| 707 |
+
|
| 708 |
+
tm.assert_equal(result, expected)
|
| 709 |
+
|
| 710 |
+
def test_where_ea_other(self):
|
| 711 |
+
# GH#38729/GH#38742
|
| 712 |
+
df = DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
|
| 713 |
+
arr = pd.array([7, pd.NA, 9])
|
| 714 |
+
ser = Series(arr)
|
| 715 |
+
mask = np.ones(df.shape, dtype=bool)
|
| 716 |
+
mask[1, :] = False
|
| 717 |
+
|
| 718 |
+
# TODO: ideally we would get Int64 instead of object
|
| 719 |
+
result = df.where(mask, ser, axis=0)
|
| 720 |
+
expected = DataFrame({"A": [1, np.nan, 3], "B": [4, np.nan, 6]})
|
| 721 |
+
tm.assert_frame_equal(result, expected)
|
| 722 |
+
|
| 723 |
+
ser2 = Series(arr[:2], index=["A", "B"])
|
| 724 |
+
expected = DataFrame({"A": [1, 7, 3], "B": [4, np.nan, 6]})
|
| 725 |
+
result = df.where(mask, ser2, axis=1)
|
| 726 |
+
tm.assert_frame_equal(result, expected)
|
| 727 |
+
|
| 728 |
+
def test_where_interval_noop(self):
|
| 729 |
+
# GH#44181
|
| 730 |
+
df = DataFrame([pd.Interval(0, 0)])
|
| 731 |
+
res = df.where(df.notna())
|
| 732 |
+
tm.assert_frame_equal(res, df)
|
| 733 |
+
|
| 734 |
+
ser = df[0]
|
| 735 |
+
res = ser.where(ser.notna())
|
| 736 |
+
tm.assert_series_equal(res, ser)
|
| 737 |
+
|
| 738 |
+
def test_where_interval_fullop_downcast(self, frame_or_series):
|
| 739 |
+
# GH#45768
|
| 740 |
+
obj = frame_or_series([pd.Interval(0, 0)] * 2)
|
| 741 |
+
other = frame_or_series([1.0, 2.0])
|
| 742 |
+
|
| 743 |
+
msg = "Downcasting behavior in Series and DataFrame methods 'where'"
|
| 744 |
+
with tm.assert_produces_warning(FutureWarning, match=msg):
|
| 745 |
+
res = obj.where(~obj.notna(), other)
|
| 746 |
+
|
| 747 |
+
# since all entries are being changed, we will downcast result
|
| 748 |
+
# from object to ints (not floats)
|
| 749 |
+
tm.assert_equal(res, other.astype(np.int64))
|
| 750 |
+
|
| 751 |
+
# unlike where, Block.putmask does not downcast
|
| 752 |
+
with tm.assert_produces_warning(
|
| 753 |
+
FutureWarning, match="Setting an item of incompatible dtype"
|
| 754 |
+
):
|
| 755 |
+
obj.mask(obj.notna(), other, inplace=True)
|
| 756 |
+
tm.assert_equal(obj, other.astype(object))
|
| 757 |
+
|
| 758 |
+
@pytest.mark.parametrize(
|
| 759 |
+
"dtype",
|
| 760 |
+
[
|
| 761 |
+
"timedelta64[ns]",
|
| 762 |
+
"datetime64[ns]",
|
| 763 |
+
"datetime64[ns, Asia/Tokyo]",
|
| 764 |
+
"Period[D]",
|
| 765 |
+
],
|
| 766 |
+
)
|
| 767 |
+
def test_where_datetimelike_noop(self, dtype):
|
| 768 |
+
# GH#45135, analogue to GH#44181 for Period don't raise on no-op
|
| 769 |
+
# For td64/dt64/dt64tz we already don't raise, but also are
|
| 770 |
+
# checking that we don't unnecessarily upcast to object.
|
| 771 |
+
with tm.assert_produces_warning(FutureWarning, match="is deprecated"):
|
| 772 |
+
ser = Series(np.arange(3) * 10**9, dtype=np.int64).view(dtype)
|
| 773 |
+
df = ser.to_frame()
|
| 774 |
+
mask = np.array([False, False, False])
|
| 775 |
+
|
| 776 |
+
res = ser.where(~mask, "foo")
|
| 777 |
+
tm.assert_series_equal(res, ser)
|
| 778 |
+
|
| 779 |
+
mask2 = mask.reshape(-1, 1)
|
| 780 |
+
res2 = df.where(~mask2, "foo")
|
| 781 |
+
tm.assert_frame_equal(res2, df)
|
| 782 |
+
|
| 783 |
+
res3 = ser.mask(mask, "foo")
|
| 784 |
+
tm.assert_series_equal(res3, ser)
|
| 785 |
+
|
| 786 |
+
res4 = df.mask(mask2, "foo")
|
| 787 |
+
tm.assert_frame_equal(res4, df)
|
| 788 |
+
|
| 789 |
+
# opposite case where we are replacing *all* values -> we downcast
|
| 790 |
+
# from object dtype # GH#45768
|
| 791 |
+
msg = "Downcasting behavior in Series and DataFrame methods 'where'"
|
| 792 |
+
with tm.assert_produces_warning(FutureWarning, match=msg):
|
| 793 |
+
res5 = df.where(mask2, 4)
|
| 794 |
+
expected = DataFrame(4, index=df.index, columns=df.columns)
|
| 795 |
+
tm.assert_frame_equal(res5, expected)
|
| 796 |
+
|
| 797 |
+
# unlike where, Block.putmask does not downcast
|
| 798 |
+
with tm.assert_produces_warning(
|
| 799 |
+
FutureWarning, match="Setting an item of incompatible dtype"
|
| 800 |
+
):
|
| 801 |
+
df.mask(~mask2, 4, inplace=True)
|
| 802 |
+
tm.assert_frame_equal(df, expected.astype(object))
|
| 803 |
+
|
| 804 |
+
|
| 805 |
+
def test_where_int_downcasting_deprecated():
|
| 806 |
+
# GH#44597
|
| 807 |
+
arr = np.arange(6).astype(np.int16).reshape(3, 2)
|
| 808 |
+
df = DataFrame(arr)
|
| 809 |
+
|
| 810 |
+
mask = np.zeros(arr.shape, dtype=bool)
|
| 811 |
+
mask[:, 0] = True
|
| 812 |
+
|
| 813 |
+
res = df.where(mask, 2**17)
|
| 814 |
+
|
| 815 |
+
expected = DataFrame({0: arr[:, 0], 1: np.array([2**17] * 3, dtype=np.int32)})
|
| 816 |
+
tm.assert_frame_equal(res, expected)
|
| 817 |
+
|
| 818 |
+
|
| 819 |
+
def test_where_copies_with_noop(frame_or_series):
|
| 820 |
+
# GH-39595
|
| 821 |
+
result = frame_or_series([1, 2, 3, 4])
|
| 822 |
+
expected = result.copy()
|
| 823 |
+
col = result[0] if frame_or_series is DataFrame else result
|
| 824 |
+
|
| 825 |
+
where_res = result.where(col < 5)
|
| 826 |
+
where_res *= 2
|
| 827 |
+
|
| 828 |
+
tm.assert_equal(result, expected)
|
| 829 |
+
|
| 830 |
+
where_res = result.where(col > 5, [1, 2, 3, 4])
|
| 831 |
+
where_res *= 2
|
| 832 |
+
|
| 833 |
+
tm.assert_equal(result, expected)
|
| 834 |
+
|
| 835 |
+
|
| 836 |
+
def test_where_string_dtype(frame_or_series):
|
| 837 |
+
# GH40824
|
| 838 |
+
obj = frame_or_series(
|
| 839 |
+
["a", "b", "c", "d"], index=["id1", "id2", "id3", "id4"], dtype=StringDtype()
|
| 840 |
+
)
|
| 841 |
+
filtered_obj = frame_or_series(
|
| 842 |
+
["b", "c"], index=["id2", "id3"], dtype=StringDtype()
|
| 843 |
+
)
|
| 844 |
+
filter_ser = Series([False, True, True, False])
|
| 845 |
+
|
| 846 |
+
result = obj.where(filter_ser, filtered_obj)
|
| 847 |
+
expected = frame_or_series(
|
| 848 |
+
[pd.NA, "b", "c", pd.NA],
|
| 849 |
+
index=["id1", "id2", "id3", "id4"],
|
| 850 |
+
dtype=StringDtype(),
|
| 851 |
+
)
|
| 852 |
+
tm.assert_equal(result, expected)
|
| 853 |
+
|
| 854 |
+
result = obj.mask(~filter_ser, filtered_obj)
|
| 855 |
+
tm.assert_equal(result, expected)
|
| 856 |
+
|
| 857 |
+
obj.mask(~filter_ser, filtered_obj, inplace=True)
|
| 858 |
+
tm.assert_equal(result, expected)
|
| 859 |
+
|
| 860 |
+
|
| 861 |
+
def test_where_bool_comparison():
|
| 862 |
+
# GH 10336
|
| 863 |
+
df_mask = DataFrame(
|
| 864 |
+
{"AAA": [True] * 4, "BBB": [False] * 4, "CCC": [True, False, True, False]}
|
| 865 |
+
)
|
| 866 |
+
result = df_mask.where(df_mask == False) # noqa: E712
|
| 867 |
+
expected = DataFrame(
|
| 868 |
+
{
|
| 869 |
+
"AAA": np.array([np.nan] * 4, dtype=object),
|
| 870 |
+
"BBB": [False] * 4,
|
| 871 |
+
"CCC": [np.nan, False, np.nan, False],
|
| 872 |
+
}
|
| 873 |
+
)
|
| 874 |
+
tm.assert_frame_equal(result, expected)
|
| 875 |
+
|
| 876 |
+
|
| 877 |
+
def test_where_none_nan_coerce():
|
| 878 |
+
# GH 15613
|
| 879 |
+
expected = DataFrame(
|
| 880 |
+
{
|
| 881 |
+
"A": [Timestamp("20130101"), pd.NaT, Timestamp("20130103")],
|
| 882 |
+
"B": [1, 2, np.nan],
|
| 883 |
+
}
|
| 884 |
+
)
|
| 885 |
+
result = expected.where(expected.notnull(), None)
|
| 886 |
+
tm.assert_frame_equal(result, expected)
|
| 887 |
+
|
| 888 |
+
|
| 889 |
+
def test_where_duplicate_axes_mixed_dtypes():
|
| 890 |
+
# GH 25399, verify manually masking is not affected anymore by dtype of column for
|
| 891 |
+
# duplicate axes.
|
| 892 |
+
result = DataFrame(data=[[0, np.nan]], columns=Index(["A", "A"]))
|
| 893 |
+
index, columns = result.axes
|
| 894 |
+
mask = DataFrame(data=[[True, True]], columns=columns, index=index)
|
| 895 |
+
a = result.astype(object).where(mask)
|
| 896 |
+
b = result.astype("f8").where(mask)
|
| 897 |
+
c = result.T.where(mask.T).T
|
| 898 |
+
d = result.where(mask) # used to fail with "cannot reindex from a duplicate axis"
|
| 899 |
+
tm.assert_frame_equal(a.astype("f8"), b.astype("f8"))
|
| 900 |
+
tm.assert_frame_equal(b.astype("f8"), c.astype("f8"))
|
| 901 |
+
tm.assert_frame_equal(c.astype("f8"), d.astype("f8"))
|
| 902 |
+
|
| 903 |
+
|
| 904 |
+
def test_where_columns_casting():
|
| 905 |
+
# GH 42295
|
| 906 |
+
|
| 907 |
+
df = DataFrame({"a": [1.0, 2.0], "b": [3, np.nan]})
|
| 908 |
+
expected = df.copy()
|
| 909 |
+
result = df.where(pd.notnull(df), None)
|
| 910 |
+
# make sure dtypes don't change
|
| 911 |
+
tm.assert_frame_equal(expected, result)
|
| 912 |
+
|
| 913 |
+
|
| 914 |
+
@pytest.mark.parametrize("as_cat", [True, False])
|
| 915 |
+
def test_where_period_invalid_na(frame_or_series, as_cat, request):
|
| 916 |
+
# GH#44697
|
| 917 |
+
idx = pd.period_range("2016-01-01", periods=3, freq="D")
|
| 918 |
+
if as_cat:
|
| 919 |
+
idx = idx.astype("category")
|
| 920 |
+
obj = frame_or_series(idx)
|
| 921 |
+
|
| 922 |
+
# NA value that we should *not* cast to Period dtype
|
| 923 |
+
tdnat = pd.NaT.to_numpy("m8[ns]")
|
| 924 |
+
|
| 925 |
+
mask = np.array([True, True, False], ndmin=obj.ndim).T
|
| 926 |
+
|
| 927 |
+
if as_cat:
|
| 928 |
+
msg = (
|
| 929 |
+
r"Cannot setitem on a Categorical with a new category \(NaT\), "
|
| 930 |
+
"set the categories first"
|
| 931 |
+
)
|
| 932 |
+
else:
|
| 933 |
+
msg = "value should be a 'Period'"
|
| 934 |
+
|
| 935 |
+
if as_cat:
|
| 936 |
+
with pytest.raises(TypeError, match=msg):
|
| 937 |
+
obj.where(mask, tdnat)
|
| 938 |
+
|
| 939 |
+
with pytest.raises(TypeError, match=msg):
|
| 940 |
+
obj.mask(mask, tdnat)
|
| 941 |
+
|
| 942 |
+
with pytest.raises(TypeError, match=msg):
|
| 943 |
+
obj.mask(mask, tdnat, inplace=True)
|
| 944 |
+
|
| 945 |
+
else:
|
| 946 |
+
# With PeriodDtype, ser[i] = tdnat coerces instead of raising,
|
| 947 |
+
# so for consistency, ser[mask] = tdnat must as well
|
| 948 |
+
expected = obj.astype(object).where(mask, tdnat)
|
| 949 |
+
result = obj.where(mask, tdnat)
|
| 950 |
+
tm.assert_equal(result, expected)
|
| 951 |
+
|
| 952 |
+
expected = obj.astype(object).mask(mask, tdnat)
|
| 953 |
+
result = obj.mask(mask, tdnat)
|
| 954 |
+
tm.assert_equal(result, expected)
|
| 955 |
+
|
| 956 |
+
with tm.assert_produces_warning(
|
| 957 |
+
FutureWarning, match="Setting an item of incompatible dtype"
|
| 958 |
+
):
|
| 959 |
+
obj.mask(mask, tdnat, inplace=True)
|
| 960 |
+
tm.assert_equal(obj, expected)
|
| 961 |
+
|
| 962 |
+
|
| 963 |
+
def test_where_nullable_invalid_na(frame_or_series, any_numeric_ea_dtype):
|
| 964 |
+
# GH#44697
|
| 965 |
+
arr = pd.array([1, 2, 3], dtype=any_numeric_ea_dtype)
|
| 966 |
+
obj = frame_or_series(arr)
|
| 967 |
+
|
| 968 |
+
mask = np.array([True, True, False], ndmin=obj.ndim).T
|
| 969 |
+
|
| 970 |
+
msg = r"Invalid value '.*' for dtype (U?Int|Float)\d{1,2}"
|
| 971 |
+
|
| 972 |
+
for null in tm.NP_NAT_OBJECTS + [pd.NaT]:
|
| 973 |
+
# NaT is an NA value that we should *not* cast to pd.NA dtype
|
| 974 |
+
with pytest.raises(TypeError, match=msg):
|
| 975 |
+
obj.where(mask, null)
|
| 976 |
+
|
| 977 |
+
with pytest.raises(TypeError, match=msg):
|
| 978 |
+
obj.mask(mask, null)
|
| 979 |
+
|
| 980 |
+
|
| 981 |
+
@given(data=OPTIONAL_ONE_OF_ALL)
|
| 982 |
+
def test_where_inplace_casting(data):
|
| 983 |
+
# GH 22051
|
| 984 |
+
df = DataFrame({"a": data})
|
| 985 |
+
df_copy = df.where(pd.notnull(df), None).copy()
|
| 986 |
+
df.where(pd.notnull(df), None, inplace=True)
|
| 987 |
+
tm.assert_equal(df, df_copy)
|
| 988 |
+
|
| 989 |
+
|
| 990 |
+
def test_where_downcast_to_td64():
|
| 991 |
+
ser = Series([1, 2, 3])
|
| 992 |
+
|
| 993 |
+
mask = np.array([False, False, False])
|
| 994 |
+
|
| 995 |
+
td = pd.Timedelta(days=1)
|
| 996 |
+
|
| 997 |
+
msg = "Downcasting behavior in Series and DataFrame methods 'where'"
|
| 998 |
+
with tm.assert_produces_warning(FutureWarning, match=msg):
|
| 999 |
+
res = ser.where(mask, td)
|
| 1000 |
+
expected = Series([td, td, td], dtype="m8[ns]")
|
| 1001 |
+
tm.assert_series_equal(res, expected)
|
| 1002 |
+
|
| 1003 |
+
with pd.option_context("future.no_silent_downcasting", True):
|
| 1004 |
+
with tm.assert_produces_warning(None, match=msg):
|
| 1005 |
+
res2 = ser.where(mask, td)
|
| 1006 |
+
expected2 = expected.astype(object)
|
| 1007 |
+
tm.assert_series_equal(res2, expected2)
|
| 1008 |
+
|
| 1009 |
+
|
| 1010 |
+
def _check_where_equivalences(df, mask, other, expected):
|
| 1011 |
+
# similar to tests.series.indexing.test_setitem.SetitemCastingEquivalences
|
| 1012 |
+
# but with DataFrame in mind and less fleshed-out
|
| 1013 |
+
res = df.where(mask, other)
|
| 1014 |
+
tm.assert_frame_equal(res, expected)
|
| 1015 |
+
|
| 1016 |
+
res = df.mask(~mask, other)
|
| 1017 |
+
tm.assert_frame_equal(res, expected)
|
| 1018 |
+
|
| 1019 |
+
# Note: frame.mask(~mask, other, inplace=True) takes some more work bc
|
| 1020 |
+
# Block.putmask does *not* downcast. The change to 'expected' here
|
| 1021 |
+
# is specific to the cases in test_where_dt64_2d.
|
| 1022 |
+
df = df.copy()
|
| 1023 |
+
df.mask(~mask, other, inplace=True)
|
| 1024 |
+
if not mask.all():
|
| 1025 |
+
# with mask.all(), Block.putmask is a no-op, so does not downcast
|
| 1026 |
+
expected = expected.copy()
|
| 1027 |
+
expected["A"] = expected["A"].astype(object)
|
| 1028 |
+
tm.assert_frame_equal(df, expected)
|
| 1029 |
+
|
| 1030 |
+
|
| 1031 |
+
def test_where_dt64_2d():
|
| 1032 |
+
dti = date_range("2016-01-01", periods=6)
|
| 1033 |
+
dta = dti._data.reshape(3, 2)
|
| 1034 |
+
other = dta - dta[0, 0]
|
| 1035 |
+
|
| 1036 |
+
df = DataFrame(dta, columns=["A", "B"])
|
| 1037 |
+
|
| 1038 |
+
mask = np.asarray(df.isna()).copy()
|
| 1039 |
+
mask[:, 1] = True
|
| 1040 |
+
|
| 1041 |
+
# setting all of one column, none of the other
|
| 1042 |
+
expected = DataFrame({"A": other[:, 0], "B": dta[:, 1]})
|
| 1043 |
+
with tm.assert_produces_warning(
|
| 1044 |
+
FutureWarning, match="Setting an item of incompatible dtype"
|
| 1045 |
+
):
|
| 1046 |
+
_check_where_equivalences(df, mask, other, expected)
|
| 1047 |
+
|
| 1048 |
+
# setting part of one column, none of the other
|
| 1049 |
+
mask[1, 0] = True
|
| 1050 |
+
expected = DataFrame(
|
| 1051 |
+
{
|
| 1052 |
+
"A": np.array([other[0, 0], dta[1, 0], other[2, 0]], dtype=object),
|
| 1053 |
+
"B": dta[:, 1],
|
| 1054 |
+
}
|
| 1055 |
+
)
|
| 1056 |
+
with tm.assert_produces_warning(
|
| 1057 |
+
FutureWarning, match="Setting an item of incompatible dtype"
|
| 1058 |
+
):
|
| 1059 |
+
_check_where_equivalences(df, mask, other, expected)
|
| 1060 |
+
|
| 1061 |
+
# setting nothing in either column
|
| 1062 |
+
mask[:] = True
|
| 1063 |
+
expected = df
|
| 1064 |
+
_check_where_equivalences(df, mask, other, expected)
|
| 1065 |
+
|
| 1066 |
+
|
| 1067 |
+
def test_where_producing_ea_cond_for_np_dtype():
|
| 1068 |
+
# GH#44014
|
| 1069 |
+
df = DataFrame({"a": Series([1, pd.NA, 2], dtype="Int64"), "b": [1, 2, 3]})
|
| 1070 |
+
result = df.where(lambda x: x.apply(lambda y: y > 1, axis=1))
|
| 1071 |
+
expected = DataFrame(
|
| 1072 |
+
{"a": Series([pd.NA, pd.NA, 2], dtype="Int64"), "b": [np.nan, 2, 3]}
|
| 1073 |
+
)
|
| 1074 |
+
tm.assert_frame_equal(result, expected)
|
| 1075 |
+
|
| 1076 |
+
|
| 1077 |
+
@pytest.mark.parametrize(
|
| 1078 |
+
"replacement", [0.001, True, "snake", None, datetime(2022, 5, 4)]
|
| 1079 |
+
)
|
| 1080 |
+
def test_where_int_overflow(replacement, using_infer_string, request):
|
| 1081 |
+
# GH 31687
|
| 1082 |
+
df = DataFrame([[1.0, 2e25, "nine"], [np.nan, 0.1, None]])
|
| 1083 |
+
if using_infer_string and replacement not in (None, "snake"):
|
| 1084 |
+
request.node.add_marker(
|
| 1085 |
+
pytest.mark.xfail(reason="Can't set non-string into string column")
|
| 1086 |
+
)
|
| 1087 |
+
result = df.where(pd.notnull(df), replacement)
|
| 1088 |
+
expected = DataFrame([[1.0, 2e25, "nine"], [replacement, 0.1, replacement]])
|
| 1089 |
+
|
| 1090 |
+
tm.assert_frame_equal(result, expected)
|
| 1091 |
+
|
| 1092 |
+
|
| 1093 |
+
def test_where_inplace_no_other():
|
| 1094 |
+
# GH#51685
|
| 1095 |
+
df = DataFrame({"a": [1.0, 2.0], "b": ["x", "y"]})
|
| 1096 |
+
cond = DataFrame({"a": [True, False], "b": [False, True]})
|
| 1097 |
+
df.where(cond, inplace=True)
|
| 1098 |
+
expected = DataFrame({"a": [1, np.nan], "b": [np.nan, "y"]})
|
| 1099 |
+
tm.assert_frame_equal(df, expected)
|