diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index d0afc24aaecac..2f2fe93d95fea 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -128,6 +128,7 @@ Interval Indexing ^^^^^^^^ - Bug in inserting many new columns into a :class:`DataFrame` causing incorrect subsequent indexing behavior (:issue:`38380`) +- Bug in :meth:`DataFrame.iloc.__setitem__` and :meth:`DataFrame.loc.__setitem__` with mixed dtypes when setting with a dictionary value (:issue:`38335`) - - diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index e7cf8cae28b88..693b09336fefc 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1649,8 +1649,10 @@ def _setitem_with_indexer_split_path(self, indexer, value, name: str): if isinstance(indexer[0], np.ndarray) and indexer[0].ndim > 2: raise ValueError(r"Cannot set values with ndim > 2") - if isinstance(value, ABCSeries) and name != "iloc": - value = self._align_series(indexer, value) + if (isinstance(value, ABCSeries) and name != "iloc") or isinstance(value, dict): + from pandas import Series + + value = self._align_series(indexer, Series(value)) # Ensure we have something we can iterate over info_axis = indexer[1] diff --git a/pandas/tests/indexing/test_iloc.py b/pandas/tests/indexing/test_iloc.py index 554b93c7cab5a..bfc6b820c0fc0 100644 --- a/pandas/tests/indexing/test_iloc.py +++ b/pandas/tests/indexing/test_iloc.py @@ -869,6 +869,12 @@ def test_iloc_setitem_dictionary_value(self): expected = DataFrame({"x": [1, 9], "y": [2, 99]}) tm.assert_frame_equal(df, expected) + # GH#38335 same thing, mixed dtypes + df = DataFrame({"x": [1, 2], "y": [2.0, 2.0]}) + df.iloc[1] = rhs + expected = DataFrame({"x": [1, 9], "y": [2.0, 99.0]}) + tm.assert_frame_equal(df, expected) + class TestILocErrors: # NB: this test should work for _any_ Series we can pass as diff --git a/pandas/tests/indexing/test_indexing.py b/pandas/tests/indexing/test_indexing.py index f750b3667cec2..e18a6aa3e8de0 100644 --- a/pandas/tests/indexing/test_indexing.py +++ b/pandas/tests/indexing/test_indexing.py @@ -741,13 +741,20 @@ def test_slice_with_zero_step_raises(self): s.loc[::0] def test_indexing_assignment_dict_already_exists(self): - df = DataFrame({"x": [1, 2, 6], "y": [2, 2, 8], "z": [-5, 0, 5]}).set_index("z") + index = Index([-5, 0, 5], name="z") + df = DataFrame({"x": [1, 2, 6], "y": [2, 2, 8]}, index=index) expected = df.copy() rhs = {"x": 9, "y": 99} df.loc[5] = rhs expected.loc[5] = [9, 99] tm.assert_frame_equal(df, expected) + # GH#38335 same thing, mixed dtypes + df = DataFrame({"x": [1, 2, 6], "y": [2.0, 2.0, 8.0]}, index=index) + df.loc[5] = rhs + expected = DataFrame({"x": [1, 2, 9], "y": [2.0, 2.0, 99.0]}, index=index) + tm.assert_frame_equal(df, expected) + def test_indexing_dtypes_on_empty(self): # Check that .iloc returns correct dtypes GH9983 df = DataFrame({"a": [1, 2, 3], "b": ["b", "b2", "b3"]})