diff --git a/asv_bench/benchmarks/arithmetic.py b/asv_bench/benchmarks/arithmetic.py index 496db66c78569..4f84e0a562687 100644 --- a/asv_bench/benchmarks/arithmetic.py +++ b/asv_bench/benchmarks/arithmetic.py @@ -106,6 +106,10 @@ def time_frame_op_with_series_axis0(self, opname): def time_frame_op_with_series_axis1(self, opname): getattr(operator, opname)(self.df, self.ser) + # exclude comparisons from the params for time_frame_op_with_series_axis1 + # since they do not do alignment so raise + time_frame_op_with_series_axis1.params = [params[0][6:]] + class FrameWithFrameWide: # Many-columns, mixed dtypes diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index 1fb9a81e85a83..03ea1aa5b8f9f 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -569,6 +569,7 @@ Removal of prior version deprecations/changes - Enforced deprecation of calling numpy "ufunc"s on :class:`DataFrame` with ``method="outer"``; this now raises ``NotImplementedError`` (:issue:`36955`) - Enforced deprecation disallowing passing ``numeric_only=True`` to :class:`Series` reductions (``rank``, ``any``, ``all``, ...) with non-numeric dtype (:issue:`47500`) - Changed behavior of :meth:`DataFrameGroupBy.apply` and :meth:`SeriesGroupBy.apply` so that ``group_keys`` is respected even if a transformer is detected (:issue:`34998`) +- Comparisons between a :class:`DataFrame` and a :class:`Series` where the frame's columns do not match the series's index raise ``ValueError`` instead of automatically aligning, do ``left, right = left.align(right, axis=1, copy=False)`` before comparing (:issue:`36795`) - Enforced deprecation ``numeric_only=None`` (the default) in DataFrame reductions that would silently drop columns that raised; ``numeric_only`` now defaults to ``False`` (:issue:`41480`) - Changed default of ``numeric_only`` to ``False`` in all DataFrame methods with that argument (:issue:`46096`, :issue:`46906`) - Changed default of ``numeric_only`` to ``False`` in :meth:`Series.rank` (:issue:`47561`) diff --git a/pandas/core/ops/__init__.py b/pandas/core/ops/__init__.py index af27ff67599ac..bfedaca093a8e 100644 --- a/pandas/core/ops/__init__.py +++ b/pandas/core/ops/__init__.py @@ -7,7 +7,6 @@ import operator from typing import TYPE_CHECKING -import warnings import numpy as np @@ -18,7 +17,6 @@ Level, ) from pandas.util._decorators import Appender -from pandas.util._exceptions import find_stack_level from pandas.core.dtypes.common import ( is_array_like, @@ -299,13 +297,10 @@ def to_series(right): 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=find_stack_level(), + raise ValueError( + "Operands are not aligned. Do " + "`left, right = left.align(right, axis=1, copy=False)` " + "before operating." ) left, right = left.align( diff --git a/pandas/tests/arithmetic/test_datetime64.py b/pandas/tests/arithmetic/test_datetime64.py index bad5335ad2d58..b4f1c5404d178 100644 --- a/pandas/tests/arithmetic/test_datetime64.py +++ b/pandas/tests/arithmetic/test_datetime64.py @@ -307,43 +307,60 @@ def test_timestamp_compare_series(self, left, right): def test_dt64arr_timestamp_equality(self, box_with_array): # GH#11034 + box = box_with_array ser = Series([Timestamp("2000-01-29 01:59:00"), Timestamp("2000-01-30"), NaT]) - ser = tm.box_expected(ser, box_with_array) + ser = tm.box_expected(ser, box) xbox = get_upcast_box(ser, ser, True) result = ser != ser expected = tm.box_expected([False, False, True], xbox) tm.assert_equal(result, expected) - warn = FutureWarning if box_with_array is pd.DataFrame else None - with tm.assert_produces_warning(warn): + if box is pd.DataFrame: # alignment for frame vs series comparisons deprecated + # in GH#46795 enforced 2.0 + with pytest.raises(ValueError, match="not aligned"): + ser != ser[0] + + else: result = ser != ser[0] - expected = tm.box_expected([False, True, True], xbox) - tm.assert_equal(result, expected) + expected = tm.box_expected([False, True, True], xbox) + tm.assert_equal(result, expected) - with tm.assert_produces_warning(warn): + if box is pd.DataFrame: # alignment for frame vs series comparisons deprecated + # in GH#46795 enforced 2.0 + with pytest.raises(ValueError, match="not aligned"): + ser != ser[2] + else: result = ser != ser[2] - expected = tm.box_expected([True, True, True], xbox) - tm.assert_equal(result, expected) + expected = tm.box_expected([True, True, True], xbox) + tm.assert_equal(result, expected) result = ser == ser expected = tm.box_expected([True, True, False], xbox) tm.assert_equal(result, expected) - with tm.assert_produces_warning(warn): + if box is pd.DataFrame: # alignment for frame vs series comparisons deprecated + # in GH#46795 enforced 2.0 + with pytest.raises(ValueError, match="not aligned"): + ser == ser[0] + else: result = ser == ser[0] - expected = tm.box_expected([True, False, False], xbox) - tm.assert_equal(result, expected) + expected = tm.box_expected([True, False, False], xbox) + tm.assert_equal(result, expected) - with tm.assert_produces_warning(warn): + if box is pd.DataFrame: # alignment for frame vs series comparisons deprecated + # in GH#46795 enforced 2.0 + with pytest.raises(ValueError, match="not aligned"): + ser == ser[2] + else: result = ser == ser[2] - expected = tm.box_expected([False, False, False], xbox) - tm.assert_equal(result, expected) + expected = tm.box_expected([False, False, False], xbox) + tm.assert_equal(result, expected) @pytest.mark.parametrize( "datetimelike", diff --git a/pandas/tests/frame/test_arithmetic.py b/pandas/tests/frame/test_arithmetic.py index 545482e6d3dad..8aedac036c2c9 100644 --- a/pandas/tests/frame/test_arithmetic.py +++ b/pandas/tests/frame/test_arithmetic.py @@ -1164,19 +1164,15 @@ def test_frame_with_zero_len_series_corner_cases(): expected = DataFrame(df.values * np.nan, columns=df.columns) tm.assert_frame_equal(result, expected) - with tm.assert_produces_warning(FutureWarning): - # Automatic alignment for comparisons deprecated - result = df == ser - expected = DataFrame(False, index=df.index, columns=df.columns) - tm.assert_frame_equal(result, expected) + with pytest.raises(ValueError, match="not aligned"): + # Automatic alignment for comparisons deprecated GH#36795, enforced 2.0 + df == ser - # non-float case should not raise on comparison + # non-float case should not raise TypeError on comparison df2 = DataFrame(df.values.view("M8[ns]"), columns=df.columns) - with tm.assert_produces_warning(FutureWarning): + with pytest.raises(ValueError, match="not aligned"): # Automatic alignment for comparisons deprecated - result = df2 == ser - expected = DataFrame(False, index=df.index, columns=df.columns) - tm.assert_frame_equal(result, expected) + df2 == ser def test_zero_len_frame_with_series_corner_cases(): diff --git a/pandas/tests/generic/test_finalize.py b/pandas/tests/generic/test_finalize.py index a7551af68bc2b..c39973d7649e8 100644 --- a/pandas/tests/generic/test_finalize.py +++ b/pandas/tests/generic/test_finalize.py @@ -476,9 +476,6 @@ def test_finalize_called_eval_numexpr(): # Binary operations -@pytest.mark.filterwarnings( - "ignore:Automatic reindexing on DataFrame vs Series:FutureWarning" -) @pytest.mark.parametrize("annotate", ["left", "right", "both"]) @pytest.mark.parametrize( "args", @@ -504,6 +501,20 @@ def test_binops(request, args, annotate, all_binary_operators): if annotate in {"left", "both"} and not isinstance(right, int): right.attrs = {"a": 1} + is_cmp = all_binary_operators in [ + operator.eq, + operator.ne, + operator.gt, + operator.ge, + operator.lt, + operator.le, + ] + if is_cmp and isinstance(left, pd.DataFrame) and isinstance(right, pd.Series): + # in 2.0 silent alignment on comparisons was removed xref GH#28759 + left, right = left.align(right, axis=1, copy=False) + elif is_cmp and isinstance(left, pd.Series) and isinstance(right, pd.DataFrame): + right, left = right.align(left, axis=1, copy=False) + result = all_binary_operators(left, right) assert result.attrs == {"a": 1}