From c94caeb3fc4c8cebd352a26bddb6cce308ed9fc1 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Sat, 10 Aug 2019 21:39:17 +0200 Subject: [PATCH 1/3] BUG: add back check for MultiIndex case and take_split_path --- pandas/core/indexing.py | 13 +++++++++++++ pandas/tests/indexing/multiindex/test_loc.py | 12 ++++++++++++ 2 files changed, 25 insertions(+) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index e308ae03730b3..88a7b0ee04c97 100755 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -321,6 +321,19 @@ def _setitem_with_indexer(self, indexer, value): val = list(value.values()) if isinstance(value, dict) else value take_split_path = not blk._can_hold_element(val) + if isinstance(indexer, tuple) and len(indexer) == len(self.obj.axes): + + for i, ax in zip(indexer, self.obj.axes): + + # if we have any multi-indexes that have non-trivial slices + # (not null slices) then we must take the split path, xref + # GH 10360 + if isinstance(ax, MultiIndex) and not ( + is_integer(i) or com.is_null_slice(i) + ): + take_split_path = True + break + if isinstance(indexer, tuple): nindexer = [] for i, idx in enumerate(indexer): diff --git a/pandas/tests/indexing/multiindex/test_loc.py b/pandas/tests/indexing/multiindex/test_loc.py index a08b2b4c66af2..f063c50210ced 100644 --- a/pandas/tests/indexing/multiindex/test_loc.py +++ b/pandas/tests/indexing/multiindex/test_loc.py @@ -390,3 +390,15 @@ def test_loc_getitem_lowerdim_corner(multiindex_dataframe_random_data): expected = 0 result = df.sort_index().loc[("bar", "three"), "B"] assert result == expected + + +def test_loc_setitem_object_array(): + # case from https://github.com/pandas-dev/pandas/issues/27841 + df = DataFrame( + "string", + index=list("abcd"), + columns=MultiIndex.from_product([["Main"], ("another", "one")]), + ) + df["labels"] = "a" + df.loc[:, "labels"] = df.index + tm.assert_numpy_array_equal(np.asarray(df["labels"]), np.asarray(df.index)) From 3e20f32ff9a54441777a43b76e98783186b08b52 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Mon, 12 Aug 2019 09:36:27 +0200 Subject: [PATCH 2/3] update comment --- pandas/core/indexing.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 88a7b0ee04c97..ea00737f776ee 100755 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -321,13 +321,11 @@ def _setitem_with_indexer(self, indexer, value): val = list(value.values()) if isinstance(value, dict) else value take_split_path = not blk._can_hold_element(val) + # if we have any multi-indexes that have non-trivial slices + # (not null slices) then we must take the split path, xref + # GH 10360, GH 27841 if isinstance(indexer, tuple) and len(indexer) == len(self.obj.axes): - for i, ax in zip(indexer, self.obj.axes): - - # if we have any multi-indexes that have non-trivial slices - # (not null slices) then we must take the split path, xref - # GH 10360 if isinstance(ax, MultiIndex) and not ( is_integer(i) or com.is_null_slice(i) ): From a5adb2e99a068578cdcc96b7cbdf1f064220f1c4 Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Mon, 12 Aug 2019 09:49:03 +0200 Subject: [PATCH 3/3] add simpler test + whatsnew --- doc/source/whatsnew/v0.25.1.rst | 2 +- pandas/tests/indexing/multiindex/test_loc.py | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v0.25.1.rst b/doc/source/whatsnew/v0.25.1.rst index 637ac5c9c8bd1..9a435e1d18640 100644 --- a/doc/source/whatsnew/v0.25.1.rst +++ b/doc/source/whatsnew/v0.25.1.rst @@ -84,7 +84,7 @@ Indexing - Bug in partial-string indexing returning a NumPy array rather than a ``Series`` when indexing with a scalar like ``.loc['2015']`` (:issue:`27516`) - Break reference cycle involving :class:`Index` to allow garbage collection of :class:`Index` objects without running the GC. (:issue:`27585`) -- +- Fix regression in assigning values to a single column of a DataFrame with a ``MultiIndex`` columns (:issue:`27841`). - Missing diff --git a/pandas/tests/indexing/multiindex/test_loc.py b/pandas/tests/indexing/multiindex/test_loc.py index f063c50210ced..8b48c2bf7169f 100644 --- a/pandas/tests/indexing/multiindex/test_loc.py +++ b/pandas/tests/indexing/multiindex/test_loc.py @@ -392,7 +392,7 @@ def test_loc_getitem_lowerdim_corner(multiindex_dataframe_random_data): assert result == expected -def test_loc_setitem_object_array(): +def test_loc_setitem_single_column_slice(): # case from https://github.com/pandas-dev/pandas/issues/27841 df = DataFrame( "string", @@ -402,3 +402,14 @@ def test_loc_setitem_object_array(): df["labels"] = "a" df.loc[:, "labels"] = df.index tm.assert_numpy_array_equal(np.asarray(df["labels"]), np.asarray(df.index)) + + # test with non-object block + df = DataFrame( + np.nan, + index=range(4), + columns=MultiIndex.from_tuples([("A", "1"), ("A", "2"), ("B", "1")]), + ) + expected = df.copy() + df.loc[:, "B"] = np.arange(4) + expected.iloc[:, 2] = np.arange(4) + tm.assert_frame_equal(df, expected)