Skip to content

Commit 00c7ccd

Browse files
committed
BUG: Fix MultiIndex .loc with all numpy arrays
1 parent b585e3b commit 00c7ccd

File tree

3 files changed

+43
-3
lines changed

3 files changed

+43
-3
lines changed

doc/source/whatsnew/v0.23.0.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,7 @@ MultiIndex
833833
- Bug in :func:`MultiIndex.get_loc` which would cast boolean to integer labels (:issue:`19086`)
834834
- Bug in :func:`MultiIndex.get_loc` which would fail to locate keys containing ``NaN`` (:issue:`18485`)
835835
- Bug in :func:`MultiIndex.get_loc` in large :class:`MultiIndex`, would fail when levels had different dtypes (:issue:`18520`)
836+
- Bug in indexing where nested indexers having only numpy arrays are handled incorrectly (:issue:`19686`)
836837

837838

838839
I/O

pandas/core/indexing.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2107,10 +2107,9 @@ def is_nested_tuple(tup, labels):
21072107
if not isinstance(tup, tuple):
21082108
return False
21092109

2110-
# are we nested tuple of: tuple,list,slice
21112110
for i, k in enumerate(tup):
21122111

2113-
if isinstance(k, (tuple, list, slice)):
2112+
if is_list_like(k) or isinstance(k, slice):
21142113
return isinstance(labels, MultiIndex)
21152114

21162115
return False

pandas/tests/indexing/test_loc.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import pandas as pd
1010
from pandas.compat import lrange, StringIO
11-
from pandas import Series, DataFrame, Timestamp, date_range, MultiIndex
11+
from pandas import Series, DataFrame, Timestamp, date_range, MultiIndex, Index
1212
from pandas.util import testing as tm
1313
from pandas.tests.indexing.common import Base
1414

@@ -711,3 +711,43 @@ def test_identity_slice_returns_new_object(self):
711711

712712
original_series[:3] = [7, 8, 9]
713713
assert all(sliced_series[:3] == [7, 8, 9])
714+
715+
@pytest.mark.parametrize(
716+
'indexer_type_1',
717+
(list, tuple, set, slice, np.ndarray, Series, Index))
718+
@pytest.mark.parametrize(
719+
'indexer_type_2',
720+
(list, tuple, set, slice, np.ndarray, Series, Index))
721+
def test_loc_getitem_nested_indexer(self, indexer_type_1, indexer_type_2):
722+
# GH #19686
723+
# .loc should work with nested indexers which can be
724+
# any list-like objects (see `pandas.api.types.is_list_like`) or slices
725+
726+
def convert_nested_indexer(indexer_type, keys):
727+
if indexer_type == np.ndarray:
728+
return np.array(keys)
729+
if indexer_type == slice:
730+
return slice(*keys)
731+
return indexer_type(keys)
732+
733+
a = [10, 20, 30]
734+
b = [1, 2, 3]
735+
index = pd.MultiIndex.from_product([a, b])
736+
df = pd.DataFrame(np.arange(len(index), dtype='int64'),
737+
index=index, columns=['Data'])
738+
739+
keys = ([10, 20], [2, 3])
740+
types = (indexer_type_1, indexer_type_2)
741+
742+
# check indexers with all the combinations of nested objects
743+
# of all the valid types
744+
indexer = tuple(
745+
convert_nested_indexer(indexer_type, k)
746+
for indexer_type, k in zip(types, keys))
747+
748+
result = df.loc[indexer, 'Data']
749+
expected = pd.Series(
750+
[1, 2, 4, 5], name='Data',
751+
index=pd.MultiIndex.from_product(keys))
752+
753+
tm.assert_series_equal(result, expected)

0 commit comments

Comments
 (0)