From 37b4156bd1952e46f50bd4f40e03a11a5759e9d9 Mon Sep 17 00:00:00 2001 From: Brock Date: Fri, 25 Jun 2021 10:07:53 -0700 Subject: [PATCH 1/2] PERF: tighten _should_compare for MultiIndex --- pandas/core/indexes/base.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 6219aa07478d7..cb83ed40f2526 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -5289,6 +5289,16 @@ def _get_indexer_non_comparable( """ if method is not None: other = unpack_nested_dtype(target) + if self._is_multi ^ other._is_multi: + kind = other.dtype.type if self._is_multi else self.dtype.type + raise TypeError( + f"'<' not supported between instances of {kind} and 'tuple'" + ) + elif self._is_multi and other._is_multi: + assert self.nlevels != other.nlevels + # Python allows comparison between tuples of different lengths, + # but for our purposes such a comparison is not meaningful. + raise TypeError("'<' not supported between tuples of different lengths") raise TypeError(f"Cannot compare dtypes {self.dtype} and {other.dtype}") no_matches = -1 * np.ones(target.shape, dtype=np.intp) @@ -5418,6 +5428,14 @@ def _should_compare(self, other: Index) -> bool: other = unpack_nested_dtype(other) dtype = other.dtype + if other._is_multi: + if not self._is_multi: + # other contains only tuples so unless we are object-dtype, + # there can never be any matches + return self._is_comparable_dtype(dtype) + return self.nlevels == other.nlevels + # TODO: we can get more specific requiring levels are comparable? + return self._is_comparable_dtype(dtype) or is_object_dtype(dtype) def _is_comparable_dtype(self, dtype: DtypeObj) -> bool: From 795b70043c19d620aea24defb9573738bea8a95e Mon Sep 17 00:00:00 2001 From: Brock Date: Fri, 25 Jun 2021 17:45:49 -0700 Subject: [PATCH 2/2] Test for get_indexer with method and mixed-nlevels --- pandas/tests/indexes/multi/test_indexing.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pandas/tests/indexes/multi/test_indexing.py b/pandas/tests/indexes/multi/test_indexing.py index 9e1097ce5951f..ec7ddf8b4d67a 100644 --- a/pandas/tests/indexes/multi/test_indexing.py +++ b/pandas/tests/indexes/multi/test_indexing.py @@ -457,6 +457,15 @@ def test_get_indexer_kwarg_validation(self): with pytest.raises(ValueError, match=msg): mi.get_indexer(mi[:-1], tolerance="piano") + def test_get_indexer_mismatched_nlevels(self): + mi = MultiIndex.from_product([range(3), ["A", "B"]]) + + other = MultiIndex.from_product([range(3), ["A", "B"], range(2)]) + + msg = "tuples of different lengths" + with pytest.raises(TypeError, match=msg): + mi.get_indexer(other, method="pad") + def test_getitem(idx): # scalar