From d0ca15be3f2a1663e66716180acf7ab4e032c6cf Mon Sep 17 00:00:00 2001 From: Joris Van den Bossche Date: Wed, 11 Feb 2015 15:52:35 +0100 Subject: [PATCH] BUG: binary operator method alignment with integer level (GH9463) --- doc/source/whatsnew/v0.16.0.txt | 2 +- pandas/core/generic.py | 17 ++++++----------- pandas/tests/test_frame.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/doc/source/whatsnew/v0.16.0.txt b/doc/source/whatsnew/v0.16.0.txt index 0234a0dab8e28..bd5ffca3f8ecc 100644 --- a/doc/source/whatsnew/v0.16.0.txt +++ b/doc/source/whatsnew/v0.16.0.txt @@ -228,7 +228,7 @@ Bug Fixes - +- Bug in binary operator method (eg ``.mul()``) alignment with integer levels (:issue:`9463`). diff --git a/pandas/core/generic.py b/pandas/core/generic.py index b2adfae744db7..4a4dd2448d613 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -3172,20 +3172,15 @@ def _align_series(self, other, join='outer', axis=None, level=None, else: - # for join compat if we have an unnamed index, but - # are specifying a level join - other_index = other.index - if level is not None and other.index.name is None: - other_index = other_index.set_names([level]) - # one has > 1 ndim fdata = self._data if axis == 0: join_index = self.index lidx, ridx = None, None - if not self.index.equals(other_index): - join_index, lidx, ridx = self.index.join( - other_index, how=join, return_indexers=True) + if not self.index.equals(other.index): + join_index, lidx, ridx = \ + self.index.join(other.index, how=join, level=level, + return_indexers=True) if lidx is not None: fdata = fdata.reindex_indexer(join_index, lidx, axis=1) @@ -3193,9 +3188,9 @@ def _align_series(self, other, join='outer', axis=None, level=None, elif axis == 1: join_index = self.columns lidx, ridx = None, None - if not self.columns.equals(other_index): + if not self.columns.equals(other.index): join_index, lidx, ridx = \ - self.columns.join(other_index, how=join, + self.columns.join(other.index, how=join, level=level, return_indexers=True) if lidx is not None: diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py index 563e9d4dae57c..f97098f6e726f 100644 --- a/pandas/tests/test_frame.py +++ b/pandas/tests/test_frame.py @@ -5428,6 +5428,35 @@ def test_binary_ops_align(self): expected = pd.concat([ opa(df.loc[idx[:,i],:],v) for i, v in x.iteritems() ]).reindex_like(df).sortlevel() assert_frame_equal(result, expected) + ## GH9463 (alignment level of dataframe with series) + + midx = MultiIndex.from_product([['A', 'B'],['a', 'b']]) + df = DataFrame(np.ones((2,4), dtype='int64'), columns=midx) + s = pd.Series({'a':1, 'b':2}) + + df2 = df.copy() + df2.columns.names = ['lvl0', 'lvl1'] + s2 = s.copy() + s2.index.name = 'lvl1' + + # different cases of integer/string level names: + res1 = df.mul(s, axis=1, level=1) + res2 = df.mul(s2, axis=1, level=1) + res3 = df2.mul(s, axis=1, level=1) + res4 = df2.mul(s2, axis=1, level=1) + res5 = df2.mul(s, axis=1, level='lvl1') + res6 = df2.mul(s2, axis=1, level='lvl1') + + exp = DataFrame(np.array([[1, 2, 1, 2], [1, 2, 1, 2]], dtype='int64'), + columns=midx) + + for res in [res1, res2]: + assert_frame_equal(res, exp) + + exp.columns.names = ['lvl0', 'lvl1'] + for res in [res3, res4, res5, res6]: + assert_frame_equal(res, exp) + def test_arith_mixed(self): left = DataFrame({'A': ['a', 'b', 'c'],