Skip to content

Commit

Permalink
BUG: Fix MultiIndex .loc with all numpy arrays (#19772)
Browse files Browse the repository at this point in the history
  • Loading branch information
spacesphere authored and jreback committed Feb 23, 2018
1 parent 4871b48 commit 572476f
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 3 deletions.
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.23.0.txt
Expand Up @@ -836,6 +836,7 @@ MultiIndex
- Bug in :func:`MultiIndex.get_loc` which would cast boolean to integer labels (:issue:`19086`)
- Bug in :func:`MultiIndex.get_loc` which would fail to locate keys containing ``NaN`` (:issue:`18485`)
- Bug in :func:`MultiIndex.get_loc` in large :class:`MultiIndex`, would fail when levels had different dtypes (:issue:`18520`)
- Bug in indexing where nested indexers having only numpy arrays are handled incorrectly (:issue:`19686`)


I/O
Expand Down
3 changes: 1 addition & 2 deletions pandas/core/indexing.py
Expand Up @@ -2107,10 +2107,9 @@ def is_nested_tuple(tup, labels):
if not isinstance(tup, tuple):
return False

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

if isinstance(k, (tuple, list, slice)):
if is_list_like(k) or isinstance(k, slice):
return isinstance(labels, MultiIndex)

return False
Expand Down
43 changes: 42 additions & 1 deletion pandas/tests/indexing/test_loc.py
Expand Up @@ -8,7 +8,7 @@

import pandas as pd
from pandas.compat import lrange, StringIO
from pandas import Series, DataFrame, Timestamp, date_range, MultiIndex
from pandas import Series, DataFrame, Timestamp, date_range, MultiIndex, Index
from pandas.util import testing as tm
from pandas.tests.indexing.common import Base

Expand Down Expand Up @@ -711,3 +711,44 @@ def test_identity_slice_returns_new_object(self):

original_series[:3] = [7, 8, 9]
assert all(sliced_series[:3] == [7, 8, 9])

@pytest.mark.parametrize(
'indexer_type_1',
(list, tuple, set, slice, np.ndarray, Series, Index))
@pytest.mark.parametrize(
'indexer_type_2',
(list, tuple, set, slice, np.ndarray, Series, Index))
def test_loc_getitem_nested_indexer(self, indexer_type_1, indexer_type_2):
# GH #19686
# .loc should work with nested indexers which can be
# any list-like objects (see `pandas.api.types.is_list_like`) or slices

def convert_nested_indexer(indexer_type, keys):
if indexer_type == np.ndarray:
return np.array(keys)
if indexer_type == slice:
return slice(*keys)
return indexer_type(keys)

a = [10, 20, 30]
b = [1, 2, 3]
index = pd.MultiIndex.from_product([a, b])
df = pd.DataFrame(
np.arange(len(index), dtype='int64'),
index=index, columns=['Data'])

keys = ([10, 20], [2, 3])
types = (indexer_type_1, indexer_type_2)

# check indexers with all the combinations of nested objects
# of all the valid types
indexer = tuple(
convert_nested_indexer(indexer_type, k)
for indexer_type, k in zip(types, keys))

result = df.loc[indexer, 'Data']
expected = pd.Series(
[1, 2, 4, 5], name='Data',
index=pd.MultiIndex.from_product(keys))

tm.assert_series_equal(result, expected)

0 comments on commit 572476f

Please sign in to comment.