diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index 1236c672a1fa1..c854f995bd2ea 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -266,6 +266,7 @@ Deprecations - Deprecated indexing :class:`DataFrame` rows with datetime-like strings ``df[string]``, use ``df.loc[string]`` instead (:issue:`36179`) - Deprecated casting an object-dtype index of ``datetime`` objects to :class:`DatetimeIndex` in the :class:`Series` constructor (:issue:`23598`) - Deprecated :meth:`Index.is_all_dates` (:issue:`27744`) +- Deprecated automatic alignment on comparison operations between :class:`DataFrame` and :class:`Series`, do ``frame, ser = frame.align(ser, axis=1, copy=False)`` before e.g. ``frame == ser`` (:issue:`28759`) - :meth:`Rolling.count` with ``min_periods=None`` will default to the size of the window in a future version (:issue:`31302`) .. --------------------------------------------------------------------------- diff --git a/pandas/core/ops/__init__.py b/pandas/core/ops/__init__.py index f92f67e1d03d7..36e3a0e37c1ae 100644 --- a/pandas/core/ops/__init__.py +++ b/pandas/core/ops/__init__.py @@ -5,6 +5,7 @@ """ import operator from typing import TYPE_CHECKING, Optional, Set, Type +import warnings import numpy as np @@ -488,6 +489,18 @@ def to_series(right): elif isinstance(right, ABCSeries): # axis=1 is default for DataFrame-with-Series op axis = left._get_axis_number(axis) if axis is not None else 1 + + if not flex: + if not left.axes[axis].equals(right.index): + warnings.warn( + "Automatic reindexing on DataFrame vs Series comparisons " + "is deprecated and will raise ValueError in a future version. " + "Do `left, right = left.align(right, axis=1, copy=False)` " + "before e.g. `left == right`", + FutureWarning, + stacklevel=3, + ) + left, right = left.align( right, join="outer", axis=axis, level=level, copy=False ) diff --git a/pandas/tests/arithmetic/test_datetime64.py b/pandas/tests/arithmetic/test_datetime64.py index 626dd4f748e0b..46be296759088 100644 --- a/pandas/tests/arithmetic/test_datetime64.py +++ b/pandas/tests/arithmetic/test_datetime64.py @@ -318,11 +318,16 @@ def test_dt64arr_timestamp_equality(self, box_with_array): expected = tm.box_expected([False, True], xbox) tm.assert_equal(result, expected) - result = ser != ser[0] + warn = FutureWarning if box_with_array is pd.DataFrame else None + with tm.assert_produces_warning(warn): + # alignment for frame vs series comparisons deprecated + result = ser != ser[0] expected = tm.box_expected([False, True], xbox) tm.assert_equal(result, expected) - result = ser != ser[1] + with tm.assert_produces_warning(warn): + # alignment for frame vs series comparisons deprecated + result = ser != ser[1] expected = tm.box_expected([True, True], xbox) tm.assert_equal(result, expected) @@ -330,11 +335,15 @@ def test_dt64arr_timestamp_equality(self, box_with_array): expected = tm.box_expected([True, False], xbox) tm.assert_equal(result, expected) - result = ser == ser[0] + with tm.assert_produces_warning(warn): + # alignment for frame vs series comparisons deprecated + result = ser == ser[0] expected = tm.box_expected([True, False], xbox) tm.assert_equal(result, expected) - result = ser == ser[1] + with tm.assert_produces_warning(warn): + # alignment for frame vs series comparisons deprecated + result = ser == ser[1] expected = tm.box_expected([False, False], xbox) tm.assert_equal(result, expected) diff --git a/pandas/tests/frame/test_arithmetic.py b/pandas/tests/frame/test_arithmetic.py index b3aa5e403e795..d9ef19e174700 100644 --- a/pandas/tests/frame/test_arithmetic.py +++ b/pandas/tests/frame/test_arithmetic.py @@ -795,13 +795,17 @@ def test_frame_with_zero_len_series_corner_cases(): expected = pd.DataFrame(df.values * np.nan, columns=df.columns) tm.assert_frame_equal(result, expected) - result = df == ser + with tm.assert_produces_warning(FutureWarning): + # Automatic alignment for comparisons deprecated + result = df == ser expected = pd.DataFrame(False, index=df.index, columns=df.columns) tm.assert_frame_equal(result, expected) # non-float case should not raise on comparison df2 = pd.DataFrame(df.values.view("M8[ns]"), columns=df.columns) - result = df2 == ser + with tm.assert_produces_warning(FutureWarning): + # Automatic alignment for comparisons deprecated + result = df2 == ser expected = pd.DataFrame(False, index=df.index, columns=df.columns) tm.assert_frame_equal(result, expected)