Skip to content

Commit a9acc52

Browse files
authored
BUG: loc casting to object for multi block case when setting with list indexer (#49161)
* BUG: loc casting to object for multi block case when setting with list indexer * Remove xpasses * Fix windows * Adress comments * Remove condition
1 parent a17bd64 commit a9acc52

File tree

6 files changed

+27
-16
lines changed

6 files changed

+27
-16
lines changed

doc/source/whatsnew/v2.0.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ Interval
234234
Indexing
235235
^^^^^^^^
236236
- Bug in :meth:`DataFrame.reindex` filling with wrong values when indexing columns and index for ``uint`` dtypes (:issue:`48184`)
237+
- Bug in :meth:`DataFrame.loc` coercing dtypes when setting values with a list indexer (:issue:`49159`)
237238
- Bug in :meth:`DataFrame.__setitem__` raising ``ValueError`` when right hand side is :class:`DataFrame` with :class:`MultiIndex` columns (:issue:`49121`)
238239
- Bug in :meth:`DataFrame.reindex` casting dtype to ``object`` when :class:`DataFrame` has single extension array column when re-indexing ``columns`` and ``index`` (:issue:`48190`)
239240
- Bug in :func:`~DataFrame.describe` when formatting percentiles in the resulting index showed more decimals than needed (:issue:`46362`)

pandas/core/indexing.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,16 +1898,20 @@ def _setitem_with_indexer_2d_value(self, indexer, value):
18981898

18991899
ilocs = self._ensure_iterable_column_indexer(indexer[1])
19001900

1901-
# GH#7551 Note that this coerces the dtype if we are mixed
1902-
value = np.array(value, dtype=object)
1901+
if not is_array_like(value):
1902+
# cast lists to array
1903+
value = np.array(value, dtype=object)
19031904
if len(ilocs) != value.shape[1]:
19041905
raise ValueError(
19051906
"Must have equal len keys and value when setting with an ndarray"
19061907
)
19071908

19081909
for i, loc in enumerate(ilocs):
1909-
# setting with a list, re-coerces
1910-
self._setitem_single_column(loc, value[:, i].tolist(), pi)
1910+
value_col = value[:, i]
1911+
if is_object_dtype(value_col.dtype):
1912+
# casting to list so that we do type inference in setitem_single_column
1913+
value_col = value_col.tolist()
1914+
self._setitem_single_column(loc, value_col, pi)
19111915

19121916
def _setitem_with_indexer_frame_value(self, indexer, value: DataFrame, name: str):
19131917
ilocs = self._ensure_iterable_column_indexer(indexer[1])

pandas/tests/frame/indexing/test_coercion.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121

2222
class TestDataFrameSetitemCoercion:
23-
@pytest.mark.xfail(reason="Unnecessary cast.")
2423
@pytest.mark.parametrize("consolidate", [True, False])
2524
def test_loc_setitem_multiindex_columns(self, consolidate):
2625
# GH#18415 Setting values in a single column preserves dtype,
@@ -36,9 +35,7 @@ def test_loc_setitem_multiindex_columns(self, consolidate):
3635
A.loc[2:3, (1, slice(2, 3))] = np.ones((2, 2), dtype=np.float32)
3736
assert (A.dtypes == np.float32).all()
3837

39-
msg = "will attempt to set the values inplace instead"
40-
with tm.assert_produces_warning(FutureWarning, match=msg):
41-
A.loc[0:5, (1, slice(2, 3))] = np.ones((6, 2), dtype=np.float32)
38+
A.loc[0:5, (1, slice(2, 3))] = np.ones((6, 2), dtype=np.float32)
4239

4340
assert (A.dtypes == np.float32).all()
4441

@@ -119,7 +116,6 @@ def test_15231():
119116
tm.assert_series_equal(df.dtypes, exp_dtypes)
120117

121118

122-
@pytest.mark.xfail(reason="Unnecessarily upcasts to float64")
123119
def test_iloc_setitem_unnecesssary_float_upcasting():
124120
# GH#12255
125121
df = DataFrame(
@@ -132,10 +128,7 @@ def test_iloc_setitem_unnecesssary_float_upcasting():
132128
orig = df.copy()
133129

134130
values = df[0].values.reshape(2, 1)
135-
136-
msg = "will attempt to set the values inplace instead"
137-
with tm.assert_produces_warning(FutureWarning, match=msg):
138-
df.iloc[:, 0:1] = values
131+
df.iloc[:, 0:1] = values
139132

140133
tm.assert_frame_equal(df, orig)
141134

pandas/tests/frame/indexing/test_indexing.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,6 +1405,19 @@ def test_loc_named_tuple_for_midx(self):
14051405
)
14061406
tm.assert_frame_equal(result, expected)
14071407

1408+
@pytest.mark.parametrize("indexer", [["a"], "a"])
1409+
@pytest.mark.parametrize("col", [{}, {"b": 1}])
1410+
def test_set_2d_casting_date_to_int(self, col, indexer):
1411+
# GH#49159
1412+
df = DataFrame(
1413+
{"a": [Timestamp("2022-12-29"), Timestamp("2022-12-30")], **col},
1414+
)
1415+
df.loc[[1], indexer] = df["a"] + pd.Timedelta(days=1)
1416+
expected = DataFrame(
1417+
{"a": [Timestamp("2022-12-29"), Timestamp("2022-12-31")], **col},
1418+
)
1419+
tm.assert_frame_equal(df, expected)
1420+
14081421
@pytest.mark.parametrize("col", [{}, {"name": "a"}])
14091422
def test_loc_setitem_reordering_with_all_true_indexer(self, col):
14101423
# GH#48701

pandas/tests/indexing/test_indexing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ def test_multi_assign(self):
478478
{
479479
"FC": ["a", np.nan, "a", "b", "a", "b"],
480480
"PF": [0, 0, 0, 0, 1, 1],
481-
"col1": [0.0, 1.0, 4.0, 6.0, 8.0, 10.0],
481+
"col1": [0, 1, 4, 6, 8, 10],
482482
"col2": [12, 7, 16, np.nan, 20, 22],
483483
}
484484
)

pandas/tests/indexing/test_loc.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,12 +1500,12 @@ def test_loc_setitem_unsorted_multiindex_columns(self, key):
15001500
mi = MultiIndex.from_tuples([("A", 4), ("B", "3"), ("A", "2")])
15011501
df = DataFrame([[1, 2, 3], [4, 5, 6]], columns=mi)
15021502
obj = df.copy()
1503-
obj.loc[:, key] = np.zeros((2, 2), dtype=int)
1503+
obj.loc[:, key] = np.zeros((2, 2), dtype="int64")
15041504
expected = DataFrame([[0, 2, 0], [0, 5, 0]], columns=mi)
15051505
tm.assert_frame_equal(obj, expected)
15061506

15071507
df = df.sort_index(axis=1)
1508-
df.loc[:, key] = np.zeros((2, 2), dtype=int)
1508+
df.loc[:, key] = np.zeros((2, 2), dtype="int64")
15091509
expected = expected.sort_index(axis=1)
15101510
tm.assert_frame_equal(df, expected)
15111511

0 commit comments

Comments
 (0)