diff --git a/doc/source/whatsnew/v1.0.3.rst b/doc/source/whatsnew/v1.0.3.rst index 482222fbddbb8..0ca5f5f548885 100644 --- a/doc/source/whatsnew/v1.0.3.rst +++ b/doc/source/whatsnew/v1.0.3.rst @@ -16,6 +16,7 @@ including other versions of pandas. Fixed regressions ~~~~~~~~~~~~~~~~~ - Fixed regression in ``resample.agg`` when the underlying data is non-writeable (:issue:`31710`) +- Fixed regression in :class:`DataFrame` exponentiation with reindexing (:issue:`32685`) .. _whatsnew_103.bug_fixes: diff --git a/pandas/core/ops/__init__.py b/pandas/core/ops/__init__.py index ed779c5da6d14..3153a9ac28c10 100644 --- a/pandas/core/ops/__init__.py +++ b/pandas/core/ops/__init__.py @@ -711,13 +711,17 @@ def to_series(right): def _should_reindex_frame_op( - left: "DataFrame", right, axis, default_axis: int, fill_value, level + left: "DataFrame", right, op, axis, default_axis: int, fill_value, level ) -> bool: """ Check if this is an operation between DataFrames that will need to reindex. """ assert isinstance(left, ABCDataFrame) + if op is operator.pow or op is rpow: + # GH#32685 pow has special semantics for operating with null values + return False + if not isinstance(right, ABCDataFrame): return False @@ -779,7 +783,9 @@ def _arith_method_FRAME(cls, op, special): @Appender(doc) def f(self, other, axis=default_axis, level=None, fill_value=None): - if _should_reindex_frame_op(self, other, axis, default_axis, fill_value, level): + if _should_reindex_frame_op( + self, other, op, axis, default_axis, fill_value, level + ): return _frame_arith_method_with_reindex(self, other, op) self, other = _align_method_FRAME(self, other, axis, flex=True, level=level) diff --git a/pandas/tests/frame/test_arithmetic.py b/pandas/tests/frame/test_arithmetic.py index 92d86c8b602ff..b39c58b9931ab 100644 --- a/pandas/tests/frame/test_arithmetic.py +++ b/pandas/tests/frame/test_arithmetic.py @@ -823,3 +823,27 @@ def test_align_frame(self): half = ts[::2] result = ts + half.take(np.random.permutation(len(half))) tm.assert_frame_equal(result, expected) + + +def test_pow_with_realignment(): + # GH#32685 pow has special semantics for operating with null values + left = pd.DataFrame({"A": [0, 1, 2]}) + right = pd.DataFrame(index=[0, 1, 2]) + + result = left ** right + expected = pd.DataFrame({"A": [np.nan, 1.0, np.nan]}) + tm.assert_frame_equal(result, expected) + + +# TODO: move to tests.arithmetic and parametrize +def test_pow_nan_with_zero(): + left = pd.DataFrame({"A": [np.nan, np.nan, np.nan]}) + right = pd.DataFrame({"A": [0, 0, 0]}) + + expected = pd.DataFrame({"A": [1.0, 1.0, 1.0]}) + + result = left ** right + tm.assert_frame_equal(result, expected) + + result = left["A"] ** right["A"] + tm.assert_series_equal(result, expected["A"])