Skip to content

Commit f15c4bc

Browse files
authored
BUG: MultiIndex.drop does not raise if labels are partially found (#37830)
1 parent 109ae10 commit f15c4bc

File tree

3 files changed

+28
-3
lines changed

3 files changed

+28
-3
lines changed

doc/source/whatsnew/v1.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,7 @@ Indexing
627627
- Bug in indexing on a :class:`Series` or :class:`DataFrame` with a :class:`CategoricalIndex` using listlike indexer that contains elements that are in the index's ``categories`` but not in the index itself failing to raise ``KeyError`` (:issue:`37901`)
628628
- Bug on inserting a boolean label into a :class:`DataFrame` with a numeric :class:`Index` columns incorrectly casting to integer (:issue:`36319`)
629629
- Bug in :meth:`DataFrame.iloc` and :meth:`Series.iloc` aligning objects in ``__setitem__`` (:issue:`22046`)
630+
- Bug in :meth:`MultiIndex.drop` does not raise if labels are partially found (:issue:`37820`)
630631
- Bug in :meth:`DataFrame.loc` did not raise ``KeyError`` when missing combination was given with ``slice(None)`` for remaining levels (:issue:`19556`)
631632
- Bug in :meth:`DataFrame.loc` raising ``TypeError`` when non-integer slice was given to select values from :class:`MultiIndex` (:issue:`25165`, :issue:`24263`)
632633
- Bug in :meth:`DataFrame.loc` returning and assigning elements in wrong order when indexer is differently ordered than the :class:`MultiIndex` to filter (:issue:`31330`, :issue:`34603`)

pandas/core/indexes/multi.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -2143,7 +2143,7 @@ def drop(self, codes, level=None, errors="raise"):
21432143
Parameters
21442144
----------
21452145
codes : array-like
2146-
Must be a list of tuples
2146+
Must be a list of tuples when level is not specified
21472147
level : int or level name, default None
21482148
errors : str, default 'raise'
21492149
@@ -2198,10 +2198,13 @@ def _drop_from_level(self, codes, level, errors="raise"):
21982198
# are not nan and equal -1, this means they are missing in the index
21992199
nan_codes = isna(codes)
22002200
values[(np.equal(nan_codes, False)) & (values == -1)] = -2
2201+
if index.shape[0] == self.shape[0]:
2202+
values[np.equal(nan_codes, True)] = -2
22012203

2204+
not_found = codes[values == -2]
2205+
if len(not_found) != 0 and errors != "ignore":
2206+
raise KeyError(f"labels {not_found} not found in level")
22022207
mask = ~algos.isin(self.codes[i], values)
2203-
if mask.all() and errors != "ignore":
2204-
raise KeyError(f"labels {codes} not found in level")
22052208

22062209
return self[mask]
22072210

pandas/tests/indexes/multi/test_drop.py

+21
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,24 @@ def test_drop_with_nan_in_index(nulls_fixture):
147147
msg = r"labels \[Timestamp\('2001-01-01 00:00:00'\)\] not found in level"
148148
with pytest.raises(KeyError, match=msg):
149149
mi.drop(pd.Timestamp("2001"), level="date")
150+
151+
152+
def test_single_level_drop_partially_missing_elements():
153+
# GH 37820
154+
155+
mi = MultiIndex.from_tuples([(1, 2), (2, 2), (3, 2)])
156+
msg = r"labels \[4\] not found in level"
157+
with pytest.raises(KeyError, match=msg):
158+
mi.drop(4, level=0)
159+
with pytest.raises(KeyError, match=msg):
160+
mi.drop([1, 4], level=0)
161+
msg = r"labels \[nan\] not found in level"
162+
with pytest.raises(KeyError, match=msg):
163+
mi.drop([np.nan], level=0)
164+
with pytest.raises(KeyError, match=msg):
165+
mi.drop([np.nan, 1, 2, 3], level=0)
166+
167+
mi = MultiIndex.from_tuples([(np.nan, 1), (1, 2)])
168+
msg = r"labels \['a'\] not found in level"
169+
with pytest.raises(KeyError, match=msg):
170+
mi.drop([np.nan, 1, "a"], level=0)

0 commit comments

Comments
 (0)