Skip to content

Commit

Permalink
BUG: Fix DataFrame binary arithmatic operation handling of unaligned … (
Browse files Browse the repository at this point in the history
#60538)

* BUG: Fix DataFrame binary arithmatic operation handling of unaligned MultiIndex columns

* Address review comment
  • Loading branch information
snitish authored Jan 15, 2025
1 parent 817b706 commit 5c9b671
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 0 deletions.
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,7 @@ MultiIndex
- :meth:`DataFrame.melt` would not accept multiple names in ``var_name`` when the columns were a :class:`MultiIndex` (:issue:`58033`)
- :meth:`MultiIndex.insert` would not insert NA value correctly at unified location of index -1 (:issue:`59003`)
- :func:`MultiIndex.get_level_values` accessing a :class:`DatetimeIndex` does not carry the frequency attribute along (:issue:`58327`, :issue:`57949`)
- Bug in :class:`DataFrame` arithmetic operations in case of unaligned MultiIndex columns (:issue:`60498`)
-

I/O
Expand Down
17 changes: 17 additions & 0 deletions pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -7967,6 +7967,16 @@ def _arith_method_with_reindex(self, right: DataFrame, op) -> DataFrame:

new_left = left if lcol_indexer is None else left.iloc[:, lcol_indexer]
new_right = right if rcol_indexer is None else right.iloc[:, rcol_indexer]

# GH#60498 For MultiIndex column alignment
if isinstance(cols, MultiIndex):
# When overwriting column names, make a shallow copy so as to not modify
# the input DFs
new_left = new_left.copy(deep=False)
new_right = new_right.copy(deep=False)
new_left.columns = cols
new_right.columns = cols

result = op(new_left, new_right)

# Do the join on the columns instead of using left._align_for_op
Expand Down Expand Up @@ -7997,6 +8007,13 @@ def _should_reindex_frame_op(self, right, op, axis: int, fill_value, level) -> b
if not isinstance(right, DataFrame):
return False

if (
isinstance(self.columns, MultiIndex)
or isinstance(right.columns, MultiIndex)
) and not self.columns.equals(right.columns):
# GH#60498 Reindex if MultiIndexe columns are not matching
return True

if fill_value is None and level is None and axis == 1:
# TODO: any other cases we should handle here?

Expand Down
25 changes: 25 additions & 0 deletions pandas/tests/frame/test_arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2033,6 +2033,31 @@ def test_arithmetic_multiindex_align():
tm.assert_frame_equal(result, expected)


def test_arithmetic_multiindex_column_align():
# GH#60498
df1 = DataFrame(
data=100,
columns=MultiIndex.from_product(
[["1A", "1B"], ["2A", "2B"]], names=["Lev1", "Lev2"]
),
index=["C1", "C2"],
)
df2 = DataFrame(
data=np.array([[0.1, 0.25], [0.2, 0.45]]),
columns=MultiIndex.from_product([["1A", "1B"]], names=["Lev1"]),
index=["C1", "C2"],
)
expected = DataFrame(
data=np.array([[10.0, 10.0, 25.0, 25.0], [20.0, 20.0, 45.0, 45.0]]),
columns=MultiIndex.from_product(
[["1A", "1B"], ["2A", "2B"]], names=["Lev1", "Lev2"]
),
index=["C1", "C2"],
)
result = df1 * df2
tm.assert_frame_equal(result, expected)


def test_bool_frame_mult_float():
# GH 18549
df = DataFrame(True, list("ab"), list("cd"))
Expand Down

0 comments on commit 5c9b671

Please sign in to comment.