From 6c3f1848a8948127957e4d12d1bee40a8866283f Mon Sep 17 00:00:00 2001 From: jreback Date: Thu, 18 Sep 2014 08:59:48 -0400 Subject: [PATCH] BUG: inconsisten panel indexing with aligning frame (GH7763) --- pandas/core/indexing.py | 36 +++++++++++++++++++++-------------- pandas/tests/test_indexing.py | 27 ++++++++++++++++++++++++++ pandas/tests/test_panel.py | 34 +++++++++++++++++++++++++-------- 3 files changed, 75 insertions(+), 22 deletions(-) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index a99d056419ad2..27a31a13a0259 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -609,7 +609,13 @@ def _align_series(self, indexer, ser): def _align_frame(self, indexer, df): is_frame = self.obj.ndim == 2 is_panel = self.obj.ndim >= 3 + if isinstance(indexer, tuple): + + aligners = [not _is_null_slice(idx) for idx in indexer] + sum_aligners = sum(aligners) + single_aligner = sum_aligners == 1 + idx, cols = None, None sindexers = [] for i, ix in enumerate(indexer): @@ -626,13 +632,21 @@ def _align_frame(self, indexer, df): # panel if is_panel: - if len(sindexers) == 1 and idx is None and cols is None: - if sindexers[0] == 0: - df = df.T - return self.obj.conform(df, axis=sindexers[0]) - df = df.T + + # need to conform to the convention + # as we are not selecting on the items axis + # and we have a single indexer + # GH 7763 + if len(sindexers) == 1 and sindexers[0] != 0: + df = df.T + + if idx is None: + idx = df.index + if cols is None: + cols = df.columns if idx is not None and cols is not None: + if df.index.equals(idx) and df.columns.equals(cols): val = df.copy().values else: @@ -655,21 +669,15 @@ def _align_frame(self, indexer, df): val = df.reindex(index=ax).values return val - elif np.isscalar(indexer) and not is_frame: + elif np.isscalar(indexer) and is_panel: idx = self.obj.axes[1] cols = self.obj.axes[2] # by definition we are indexing on the 0th axis - if is_panel: - df = df.T - - if idx.equals(df.index) and cols.equals(df.columns): - return df.copy().values - # a passed in dataframe which is actually a transpose # of what is needed - elif idx.equals(df.columns) and cols.equals(df.index): - return df.T.copy().values + if idx.equals(df.index) and cols.equals(df.columns): + return df.copy().values return df.reindex(idx, columns=cols).values diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py index 27a6b844bccb5..7831fe811c2ff 100644 --- a/pandas/tests/test_indexing.py +++ b/pandas/tests/test_indexing.py @@ -2291,6 +2291,33 @@ def test_panel_getitem(self): test1 = panel.ix[:, "2002"] tm.assert_panel_equal(test1,test2) + def test_panel_setitem(self): + + # GH 7763 + # loc and setitem have setting differences + np.random.seed(0) + index=range(3) + columns = list('abc') + + panel = Panel({'A' : DataFrame(np.random.randn(3, 3), index=index, columns=columns), + 'B' : DataFrame(np.random.randn(3, 3), index=index, columns=columns), + 'C' : DataFrame(np.random.randn(3, 3), index=index, columns=columns) + }) + + replace = DataFrame(np.eye(3,3), index=range(3), columns=columns) + expected = Panel({ 'A' : replace, 'B' : replace, 'C' : replace }) + + p = panel.copy() + for idx in list('ABC'): + p[idx] = replace + tm.assert_panel_equal(p, expected) + + p = panel.copy() + for idx in list('ABC'): + p.loc[idx,:,:] = replace + tm.assert_panel_equal(p, expected) + + def test_panel_assignment(self): # GH3777 diff --git a/pandas/tests/test_panel.py b/pandas/tests/test_panel.py index 8234e5a1065e5..736cdf312b361 100644 --- a/pandas/tests/test_panel.py +++ b/pandas/tests/test_panel.py @@ -668,24 +668,42 @@ def test_ix_align(self): def test_ix_frame_align(self): from pandas import DataFrame - df = DataFrame(np.random.randn(2, 10)) - df.sort_index(inplace=True) - p_orig = Panel(np.random.randn(3, 10, 2)) + p_orig = tm.makePanel() + df = p_orig.ix[0].copy() + assert_frame_equal(p_orig['ItemA'],df) p = p_orig.copy() p.ix[0, :, :] = df - out = p.ix[0, :, :].T.reindex(df.index, columns=df.columns) - assert_frame_equal(out, df) + assert_panel_equal(p, p_orig) p = p_orig.copy() p.ix[0] = df - out = p.ix[0].T.reindex(df.index, columns=df.columns) - assert_frame_equal(out, df) + assert_panel_equal(p, p_orig) + + p = p_orig.copy() + p.iloc[0, :, :] = df + assert_panel_equal(p, p_orig) + + p = p_orig.copy() + p.iloc[0] = df + assert_panel_equal(p, p_orig) + + p = p_orig.copy() + p.loc['ItemA'] = df + assert_panel_equal(p, p_orig) + + p = p_orig.copy() + p.loc['ItemA', :, :] = df + assert_panel_equal(p, p_orig) + + p = p_orig.copy() + p['ItemA'] = df + assert_panel_equal(p, p_orig) p = p_orig.copy() p.ix[0, [0, 1, 3, 5], -2:] = df out = p.ix[0, [0, 1, 3, 5], -2:] - assert_frame_equal(out, df.T.reindex([0, 1, 3, 5], p.minor_axis[-2:])) + assert_frame_equal(out, df.iloc[[0,1,3,5],[2,3]]) # GH3830, panel assignent by values/frame for dtype in ['float64','int64']: