diff --git a/doc/source/whatsnew/v1.4.4.rst b/doc/source/whatsnew/v1.4.4.rst index 3d0a6e01826f8..71f3db9af02ff 100644 --- a/doc/source/whatsnew/v1.4.4.rst +++ b/doc/source/whatsnew/v1.4.4.rst @@ -20,6 +20,7 @@ Fixed regressions - Fixed regression in calling bitwise numpy ufuncs (for example, ``np.bitwise_and``) on Index objects (:issue:`46769`) - Fixed regression in :func:`cut` using a ``datetime64`` IntervalIndex as bins (:issue:`46218`) - Fixed regression in :meth:`DataFrame.select_dtypes` where ``include="number"`` included :class:`BooleanDtype` (:issue:`46870`) +- Fixed regression in :meth:`DataFrame.loc` raising error when indexing with a ``NamedTuple`` (:issue:`48124`) - Fixed regression in :meth:`DataFrame.loc` not updating the cache correctly after values were set (:issue:`47867`) - Fixed regression in :meth:`DataFrame.loc` not aligning index in some cases when setting a :class:`DataFrame` (:issue:`47578`) - Fixed regression in :meth:`DataFrame.loc` setting a length-1 array like value to a single value in the DataFrame (:issue:`46268`) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 9659e5b157d9a..a8aaf98a5bec1 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1175,6 +1175,9 @@ def _getitem_axis(self, key, axis: int): labels = self.obj._get_axis(axis) + if isinstance(key, tuple) and isinstance(labels, MultiIndex): + key = tuple(key) + if isinstance(key, slice): self._validate_key(key, axis) return self._get_slice_axis(key, axis=axis) diff --git a/pandas/tests/frame/indexing/test_indexing.py b/pandas/tests/frame/indexing/test_indexing.py index acb825c53155f..fda872a8999c0 100644 --- a/pandas/tests/frame/indexing/test_indexing.py +++ b/pandas/tests/frame/indexing/test_indexing.py @@ -1,3 +1,4 @@ +from collections import namedtuple from datetime import ( datetime, timedelta, @@ -1339,6 +1340,23 @@ def test_loc_setitem_rhs_frame(self, idxr, val): expected = DataFrame({"a": [np.nan, val]}) tm.assert_frame_equal(df, expected) + def test_loc_named_tuple_for_midx(self): + # GH#48124 + df = DataFrame( + index=MultiIndex.from_product( + [["A", "B"], ["a", "b", "c"]], names=["first", "second"] + ) + ) + indexer_tuple = namedtuple("Indexer", df.index.names) + idxr = indexer_tuple(first="A", second=["a", "b"]) + result = df.loc[idxr, :] + expected = DataFrame( + index=MultiIndex.from_tuples( + [("A", "a"), ("A", "b")], names=["first", "second"] + ) + ) + tm.assert_frame_equal(result, expected) + class TestDataFrameIndexingUInt64: def test_setitem(self, uint64_frame):