Skip to content

Commit 3b32dab

Browse files
committed
BUG: fix MultiIndex bugs described in #1401
1 parent dfaf0ea commit 3b32dab

File tree

5 files changed

+51
-4
lines changed

5 files changed

+51
-4
lines changed

RELEASE.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ pandas 0.8.0
184184
- Enable assignment of rows in mixed-type DataFrame via .ix (#1432)
185185
- Reset index mapping when grouping Series in Cython (#1423)
186186
- Fix outer/inner DataFrame.join with non-unique indexes (#1421)
187+
- Fix MultiIndex groupby bugs with empty lower levels (#1401)
187188

188189
pandas 0.7.3
189190
============

pandas/core/generic.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -501,9 +501,15 @@ def __delitem__(self, key):
501501
Delete item
502502
"""
503503
deleted = False
504-
if (hasattr(self,'columns') and
505-
isinstance(self.columns, MultiIndex)
506-
and key not in self.columns):
504+
505+
maybe_shortcut = False
506+
if hasattr(self,'columns') and isinstance(self.columns, MultiIndex):
507+
try:
508+
maybe_shortcut = key not in self.columns._engine
509+
except TypeError:
510+
pass
511+
512+
if maybe_shortcut:
507513
# Allow shorthand to delete all columns whose first len(key)
508514
# elements match key:
509515
if not isinstance(key,tuple):

pandas/core/groupby.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1101,7 +1101,13 @@ def _get_grouper(obj, key=None, axis=0, level=None, sort=True):
11011101
exclusions = []
11021102
for i, (gpr, level) in enumerate(zip(keys, levels)):
11031103
name = None
1104-
if _is_label_like(gpr):
1104+
try:
1105+
obj._data.items.get_loc(gpr)
1106+
in_axis = True
1107+
except Exception:
1108+
in_axis = False
1109+
1110+
if _is_label_like(gpr) or in_axis:
11051111
exclusions.append(gpr)
11061112
name = gpr
11071113
gpr = obj[gpr]

pandas/core/index.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,15 @@ def nlevels(self):
15111511
def levshape(self):
15121512
return tuple(len(x) for x in self.levels)
15131513

1514+
def __contains__(self, key):
1515+
hash(key)
1516+
# work around some kind of odd cython bug
1517+
try:
1518+
self.get_loc(key)
1519+
return True
1520+
except KeyError:
1521+
return False
1522+
15141523
def __reduce__(self):
15151524
"""Necessary for making this object picklable"""
15161525
object_state = list(np.ndarray.__reduce__(self))

pandas/tests/test_groupby.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1963,6 +1963,31 @@ def afunc(data):
19631963

19641964
assert_frame_equal(closure_bad, closure_good)
19651965

1966+
def test_multiindex_columns_empty_level(self):
1967+
l = [['count', 'values'], ['to filter', '']]
1968+
midx = MultiIndex.from_tuples(l)
1969+
1970+
df = DataFrame([[1L, 'A']], columns=midx)
1971+
1972+
grouped = df.groupby('to filter').groups
1973+
self.assert_(np.array_equal(grouped['A'], [0]))
1974+
1975+
grouped = df.groupby([('to filter', '')]).groups
1976+
self.assert_(np.array_equal(grouped['A'], [0]))
1977+
1978+
df = DataFrame([[1L, 'A'], [2L, 'B']], columns=midx)
1979+
1980+
expected = df.groupby('to filter').groups
1981+
result = df.groupby([('to filter', '')]).groups
1982+
self.assertEquals(result, expected)
1983+
1984+
df = DataFrame([[1L, 'A'], [2L, 'A']], columns=midx)
1985+
1986+
expected = df.groupby('to filter').groups
1987+
result = df.groupby([('to filter', '')]).groups
1988+
self.assertEquals(result, expected)
1989+
1990+
19661991
def _check_groupby(df, result, keys, field, f=lambda x: x.sum()):
19671992
tups = map(tuple, df[keys].values)
19681993
tups = com._asarray_tuplesafe(tups)

0 commit comments

Comments
 (0)