From 587cbf703087cfa0aad6b3471f9a79fb34551c67 Mon Sep 17 00:00:00 2001 From: Brock Date: Thu, 1 Jul 2021 10:00:29 -0700 Subject: [PATCH] BUG: Series.loc with MultiIndex whose first level is all-NaN --- doc/source/whatsnew/v1.4.0.rst | 2 +- pandas/core/indexes/base.py | 19 +++++++++++++------ pandas/tests/indexing/test_loc.py | 12 ++++++++++++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index 81545ada63ce5..8cd73e659af03 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -158,7 +158,7 @@ Interval Indexing ^^^^^^^^ -- +- Bug in :meth:`Series.loc` when with a :class:`MultiIndex` whose first level contains only ``np.nan`` values (:issue:`42055`) - Missing diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 53b5bf8f182bd..3b8ab6844a3c0 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1887,14 +1887,21 @@ def _drop_level_numbers(self, levnums: list[int]): new_names.pop(i) if len(new_levels) == 1: + lev = new_levels[0] - # set nan if needed - mask = new_codes[0] == -1 - result = new_levels[0].take(new_codes[0]) - if mask.any(): - result = result.putmask(mask, np.nan) + if len(lev) == 0: + # If lev is empty, lev.take will fail GH#42055 + res_values = algos.take(lev._values, new_codes[0], allow_fill=True) + result = type(lev)._simple_new(res_values, name=new_names[0]) + else: + # set nan if needed + mask = new_codes[0] == -1 + result = new_levels[0].take(new_codes[0]) + if mask.any(): + result = result.putmask(mask, np.nan) + + result._name = new_names[0] - result._name = new_names[0] return result else: from pandas.core.indexes.multi import MultiIndex diff --git a/pandas/tests/indexing/test_loc.py b/pandas/tests/indexing/test_loc.py index e96b25418d408..4d456d809692e 100644 --- a/pandas/tests/indexing/test_loc.py +++ b/pandas/tests/indexing/test_loc.py @@ -1663,6 +1663,18 @@ def test_loc_multiindex_levels_contain_values_not_in_index_anymore(self, lt_valu with pytest.raises(KeyError, match=r"\['b'\] not in index"): df.loc[df["a"] < lt_value, :].loc[["b"], :] + def test_loc_multiindex_null_slice_na_level(self): + # GH#42055 + lev1 = np.array([np.nan, np.nan]) + lev2 = ["bar", "baz"] + mi = MultiIndex.from_arrays([lev1, lev2]) + ser = Series([0, 1], index=mi) + result = ser.loc[:, "bar"] + + # TODO: should we have name="bar"? + expected = Series([0], index=[np.nan]) + tm.assert_series_equal(result, expected) + class TestLocSetitemWithExpansion: @pytest.mark.slow