Skip to content

Commit 4d29e47

Browse files
committed
BUG: fix indexing corner case with MultiIndex re: #671
1 parent b3b5140 commit 4d29e47

File tree

3 files changed

+35
-8
lines changed

3 files changed

+35
-8
lines changed

pandas/core/indexing.py

+18-5
Original file line numberDiff line numberDiff line change
@@ -101,23 +101,30 @@ def _getitem_tuple(self, tup):
101101
# no shortcut needed
102102
retval = self.obj
103103
for i, key in enumerate(tup):
104-
# hack?
104+
if i >= self.obj.ndim:
105+
raise IndexingError('Too many indexers')
106+
107+
if _is_null_slice(key):
108+
continue
109+
105110
retval = retval.ix._getitem_axis(key, axis=i)
106111

107112
return retval
108113

109114
def _getitem_lowerdim(self, tup):
110115
from pandas.core.frame import DataFrame
111116

117+
ax0 = self.obj._get_axis(0)
112118
# a bit kludgy
113-
if isinstance(self.obj._get_axis(0), MultiIndex):
119+
if isinstance(ax0, MultiIndex):
114120
try:
115121
return self._get_label(tup, axis=0)
116122
except TypeError:
117123
# slices are unhashable
118124
pass
119125
except Exception:
120-
raise
126+
if tup[0] not in ax0:
127+
raise
121128

122129
# to avoid wasted computation
123130
# df.ix[d1:d2, 0] -> columns first (True)
@@ -148,12 +155,14 @@ def _getitem_lowerdim(self, tup):
148155
raise IndexingError('not applicable')
149156

150157
def _getitem_axis(self, key, axis=0):
158+
labels = self.obj._get_axis(axis)
151159
if isinstance(key, slice):
152160
return self._get_slice_axis(key, axis=axis)
153-
elif _is_list_like(key):
161+
elif _is_list_like(key) and not (isinstance(key, tuple) and
162+
isinstance(labels, MultiIndex)):
163+
154164
return self._getitem_iterable(key, axis=axis)
155165
elif axis == 0:
156-
labels = self.obj._get_axis(0)
157166
is_int_index = _is_integer_index(labels)
158167

159168
idx = key
@@ -374,6 +383,10 @@ def _maybe_convert_ix(*args):
374383
else:
375384
return args
376385

386+
def _is_null_slice(obj):
387+
return (isinstance(obj, slice) and obj.start is None and
388+
obj.stop is None and obj.step is None)
389+
377390
def _is_integer_dtype(arr):
378391
return issubclass(arr.dtype.type, np.integer)
379392

pandas/tests/test_frame.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -2424,9 +2424,7 @@ def test_append_series_dict(self):
24242424
self.assertRaises(Exception, df.append, series)
24252425

24262426
result = df.append(series[::-1], ignore_index=True)
2427-
expected = df.append(DataFrame({0 : series[::-1]},
2428-
index=df.columns).T,
2429-
ignore_index=True)
2427+
expected = df.append(DataFrame({0 : series[::-1]}, index=df.columns).T, ignore_index=True)
24302428
assert_frame_equal(result, expected)
24312429

24322430
# dict

pandas/tests/test_multilevel.py

+16
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,22 @@ def test_frame_getitem_setitem_slice(self):
215215
self.assert_((cp.values[:4] == 0).all())
216216
self.assert_((cp.values[4:] != 0).all())
217217

218+
def test_getitem_tuple_plus_slice(self):
219+
# GH #671
220+
df = DataFrame({'a' : range(10),
221+
'b' : range(10),
222+
'c' : np.random.randn(10),
223+
'd' : np.random.randn(10)})
224+
225+
idf = df.set_index(['a', 'b'])
226+
227+
result = idf.ix[(0, 0), :]
228+
expected = idf.ix[0, 0]
229+
expected2 = idf.xs((0, 0))
230+
231+
assert_series_equal(result, expected)
232+
assert_series_equal(result, expected2)
233+
218234
def test_xs(self):
219235
xs = self.frame.xs(('bar', 'two'))
220236
xs2 = self.frame.ix[('bar', 'two')]

0 commit comments

Comments
 (0)