Skip to content

BUG: allow empty multiindex (fixes .isin regression, GH16777) #16782

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 11 commits into from
Jul 7, 2017
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.20.3.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Indexing
^^^^^^^^

- Bug in ``Float64Index`` causing an empty array instead of ``None`` to be returned from ``.get(np.nan)`` on a Series whose index did not contain any ``NaN`` s (:issue:`8569`)
- Bug in ``MultiIndex.isin`` causing an error when passing an empty iterable (:issue:`16777`)

I/O
^^^
Expand Down
14 changes: 8 additions & 6 deletions pandas/core/indexes/multi.py
Original file line number Diff line number Diff line change
Expand Up @@ -1129,10 +1129,11 @@ def from_tuples(cls, tuples, sortorder=None, names=None):
of iterables
"""
if len(tuples) == 0:
# I think this is right? Not quite sure...
raise TypeError('Cannot infer number of levels from empty list')

if isinstance(tuples, (np.ndarray, Index)):
if names is None:
msg = 'Cannot infer number of levels from empty list'
raise TypeError(msg)
arrays = [[]] * len(names)
elif isinstance(tuples, (np.ndarray, Index)):
if isinstance(tuples, Index):
tuples = tuples._values

Expand Down Expand Up @@ -2621,8 +2622,9 @@ def _wrap_joined_index(self, joined, other):
@Appender(Index.isin.__doc__)
def isin(self, values, level=None):
if level is None:
return algos.isin(self.values,
MultiIndex.from_tuples(values).values)
values = MultiIndex.from_tuples(values,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you might be able to change this to _ensure_index(values) I think (as its more idiomatic). I also don't think you will need the .values

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_ensure_index is not meant to support values for a MultiIndex I think:

In [159]: pd.core.indexes.base._ensure_index([(1, 2), (3, 4)])
Out[159]: Index([(1, 2), (3, 4)], dtype='object')

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not able to address this before 0.20.3

names=self.names).values
return algos.isin(self.values, values)
else:
num = self._get_level_number(level)
levs = self.levels[num]
Expand Down
7 changes: 7 additions & 0 deletions pandas/tests/indexes/test_multi.py
Original file line number Diff line number Diff line change
Expand Up @@ -1720,6 +1720,13 @@ def test_from_tuples(self):
idx = MultiIndex.from_tuples(((1, 2), (3, 4)), names=['a', 'b'])
assert len(idx) == 2

def test_from_tuples_empty(self):
# GH 16777
result = MultiIndex.from_tuples([], names=['a', 'b'])
expected = MultiIndex.from_arrays(arrays=[[], []],
names=['a', 'b'])
tm.assert_index_equal(result, expected)

def test_argsort(self):
result = self.index.argsort()
expected = self.index.values.argsort()
Expand Down