From d5dff4d65dd9639bd088032f0dcf37281ee90881 Mon Sep 17 00:00:00 2001 From: phofl Date: Wed, 2 Feb 2022 22:50:40 +0100 Subject: [PATCH 1/2] Regression: Loc raising when indexing mi with one level --- doc/source/whatsnew/v1.4.1.rst | 1 + pandas/core/indexes/multi.py | 7 ++++++- pandas/tests/frame/indexing/test_indexing.py | 12 ++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.4.1.rst b/doc/source/whatsnew/v1.4.1.rst index 3dd0fcdb5b87d..498ea85a04647 100644 --- a/doc/source/whatsnew/v1.4.1.rst +++ b/doc/source/whatsnew/v1.4.1.rst @@ -16,6 +16,7 @@ Fixed regressions ~~~~~~~~~~~~~~~~~ - Regression in :meth:`Series.mask` with ``inplace=True`` and ``PeriodDtype`` and an incompatible ``other`` coercing to a common dtype instead of raising (:issue:`45546`) - Regression in :func:`.assert_frame_equal` not respecting ``check_flags=False`` (:issue:`45554`) +- Regression in :meth:`DataFrame.loc.__getitem__` raising ``ValueError`` when indexing on a :class:`MultiIndex` with one level (:issue:`45779`) - Regression in :meth:`Series.fillna` with ``downcast=False`` incorrectly downcasting ``object`` dtype (:issue:`45603`) - Regression in :meth:`DataFrame.iat` setting values leading to not propagating correctly in subsequent lookups (:issue:`45684`) - Regression when setting values with :meth:`DataFrame.loc` losing :class:`Index` name if :class:`DataFrame` was empty before (:issue:`45621`) diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 3e2dc12fef24f..c0a02240cdc5a 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -3128,7 +3128,12 @@ def maybe_mi_droplevels(indexer, levels): # e.g. test_partial_string_timestamp_multiindex return indexer, self[indexer] - return indexer, maybe_mi_droplevels(indexer, [level]) + try: + result_index = maybe_mi_droplevels(indexer, [level]) + except ValueError: + result_index = self[indexer] + + return indexer, result_index def _get_level_indexer( self, key, level: int = 0, indexer: Int64Index | None = None diff --git a/pandas/tests/frame/indexing/test_indexing.py b/pandas/tests/frame/indexing/test_indexing.py index 34f00477672d6..3f69dc6c99375 100644 --- a/pandas/tests/frame/indexing/test_indexing.py +++ b/pandas/tests/frame/indexing/test_indexing.py @@ -1546,6 +1546,18 @@ def test_getitem_preserve_object_index_with_dates(self, indexer): assert ser.index.dtype == object + def test_loc_on_multiindex_one_level(self): + # GH#45779 + df = DataFrame( + data=[[0], [1]], + index=MultiIndex.from_tuples([("a",), ("b",)], names=["first"]), + ) + expected = DataFrame( + data=[[0]], index=MultiIndex.from_tuples([("a",)], names=["first"]) + ) + result = df.loc["a"] + tm.assert_frame_equal(result, expected) + class TestDepreactedIndexers: @pytest.mark.parametrize( From 971c59d1fb5bea7fc7f930f91283958e1fa4f95b Mon Sep 17 00:00:00 2001 From: phofl Date: Sun, 6 Feb 2022 21:20:18 +0100 Subject: [PATCH 2/2] Add note --- pandas/core/indexes/multi.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index c0a02240cdc5a..eb7b28570cb09 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -2995,6 +2995,10 @@ def _get_loc_level(self, key, level: int | list[int] = 0): # different name to distinguish from maybe_droplevels def maybe_mi_droplevels(indexer, levels): + """ + If level does not exist or all levels were dropped, the exception + has to be handled outside. + """ new_index = self[indexer] for i in sorted(levels, reverse=True):