Skip to content

Commit 20a85f8

Browse files
committed
Merge pull request #10838 from jreback/mi_panel
BUG: Panel setitem with a multiindex #10360 (partial)
2 parents 13cb1a7 + f07e582 commit 20a85f8

File tree

3 files changed

+51
-8
lines changed

3 files changed

+51
-8
lines changed

doc/source/whatsnew/v0.17.0.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ Bug Fixes
606606
- Bug in ``offsets.generate_range`` where ``start`` and ``end`` have finer precision than ``offset`` (:issue:`9907`)
607607
- Bug in ``pd.rolling_*`` where ``Series.name`` would be lost in the output (:issue:`10565`)
608608
- Bug in ``stack`` when index or columns are not unique. (:issue:`10417`)
609-
609+
- Bug in setting a Panel when an axis has a multi-index (:issue:`10360`)
610610

611611

612612

pandas/core/indexing.py

+11-6
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ def _setitem_with_indexer(self, indexer, value):
201201

202202
# also has the side effect of consolidating in-place
203203
from pandas import Panel, DataFrame, Series
204+
info_axis = self.obj._info_axis_number
204205

205206
# maybe partial set
206207
take_split_path = self.obj._is_mixed_type
@@ -213,6 +214,16 @@ def _setitem_with_indexer(self, indexer, value):
213214
val = list(value.values()) if isinstance(value,dict) else value
214215
take_split_path = not blk._can_hold_element(val)
215216

217+
if isinstance(indexer, tuple) and len(indexer) == len(self.obj.axes):
218+
219+
for i, ax in zip(indexer, self.obj.axes):
220+
221+
# if we have any multi-indexes that have non-trivial slices (not null slices)
222+
# then we must take the split path, xref GH 10360
223+
if isinstance(ax, MultiIndex) and not (is_integer(i) or is_null_slice(i)):
224+
take_split_path = True
225+
break
226+
216227
if isinstance(indexer, tuple):
217228
nindexer = []
218229
for i, idx in enumerate(indexer):
@@ -328,14 +339,8 @@ def _setitem_with_indexer(self, indexer, value):
328339
return self.obj.__setitem__(indexer, value)
329340

330341
# set
331-
info_axis = self.obj._info_axis_number
332342
item_labels = self.obj._get_axis(info_axis)
333343

334-
# if we have a complicated setup, take the split path
335-
if (isinstance(indexer, tuple) and
336-
any([isinstance(ax, MultiIndex) for ax in self.obj.axes])):
337-
take_split_path = True
338-
339344
# align and set the values
340345
if take_split_path:
341346

pandas/tests/test_indexing.py

+39-1
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ def test_iloc_exceeds_bounds(self):
411411
df.iloc[30]
412412
self.assertRaises(IndexError, lambda : df.iloc[-30])
413413

414-
# GH10779
414+
# GH10779
415415
# single positive/negative indexer exceeding Series bounds should raise an IndexError
416416
with tm.assertRaisesRegexp(IndexError, 'single positional indexer is out-of-bounds'):
417417
s.iloc[30]
@@ -2652,6 +2652,44 @@ def test_panel_setitem(self):
26522652
tm.assert_panel_equal(p, expected)
26532653

26542654

2655+
def test_panel_setitem_with_multiindex(self):
2656+
2657+
# 10360
2658+
# failing with a multi-index
2659+
arr = np.array([[[1,2,3],[0,0,0]],[[0,0,0],[0,0,0]]],dtype=np.float64)
2660+
2661+
# reg index
2662+
axes = dict(items=['A', 'B'], major_axis=[0, 1], minor_axis=['X', 'Y' ,'Z'])
2663+
p1 = Panel(0., **axes)
2664+
p1.iloc[0, 0, :] = [1, 2, 3]
2665+
expected = Panel(arr, **axes)
2666+
tm.assert_panel_equal(p1, expected)
2667+
2668+
# multi-indexes
2669+
axes['items'] = pd.MultiIndex.from_tuples([('A','a'), ('B','b')])
2670+
p2 = Panel(0., **axes)
2671+
p2.iloc[0, 0, :] = [1, 2, 3]
2672+
expected = Panel(arr, **axes)
2673+
tm.assert_panel_equal(p2, expected)
2674+
2675+
axes['major_axis']=pd.MultiIndex.from_tuples([('A',1),('A',2)])
2676+
p3 = Panel(0., **axes)
2677+
p3.iloc[0, 0, :] = [1, 2, 3]
2678+
expected = Panel(arr, **axes)
2679+
tm.assert_panel_equal(p3, expected)
2680+
2681+
axes['minor_axis']=pd.MultiIndex.from_product([['X'],range(3)])
2682+
p4 = Panel(0., **axes)
2683+
p4.iloc[0, 0, :] = [1, 2, 3]
2684+
expected = Panel(arr, **axes)
2685+
tm.assert_panel_equal(p4, expected)
2686+
2687+
arr = np.array([[[1,0,0],[2,0,0]],[[0,0,0],[0,0,0]]],dtype=np.float64)
2688+
p5 = Panel(0., **axes)
2689+
p5.iloc[0, :, 0] = [1, 2]
2690+
expected = Panel(arr, **axes)
2691+
tm.assert_panel_equal(p5, expected)
2692+
26552693
def test_panel_assignment(self):
26562694

26572695
# GH3777

0 commit comments

Comments
 (0)