Skip to content

DEPR: enforce ufunc, reduction diff deprecations #49717

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/source/whatsnew/v2.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,9 @@ Removal of prior version deprecations/changes
- Changed behavior of :meth:`DataFrame.apply` with list-like so that any partial failure will raise an error (:issue:`43740`)
- Changed behavior of :meth:`Series.__setitem__` with an integer key and a :class:`Float64Index` when the key is not present in the index; previously we treated the key as positional (behaving like ``series.iloc[key] = val``), now we treat it is a label (behaving like ``series.loc[key] = val``), consistent with :meth:`Series.__getitem__`` behavior (:issue:`33469`)
- Removed ``na_sentinel`` argument from :func:`factorize`, :meth:`.Index.factorize`, and :meth:`.ExtensionArray.factorize` (:issue:`47157`)
- Changed behavior of :meth:`Series.diff` and :meth:`DataFrame.diff` with :class:`ExtensionDtype` dtypes whose arrays do not implement ``diff``, these now raise ``TypeError`` rather than casting to numpy (:issue:`31025`)
- 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`)
- 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`)
Expand Down
10 changes: 3 additions & 7 deletions pandas/core/algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -1616,14 +1616,10 @@ def diff(arr, n: int, axis: AxisInt = 0):
raise ValueError(f"cannot diff {type(arr).__name__} on axis={axis}")
return op(arr, arr.shift(n))
else:
warnings.warn(
"dtype lost in 'diff()'. In the future this will raise a "
"TypeError. Convert to a suitable dtype prior to calling 'diff'.",
FutureWarning,
stacklevel=find_stack_level(),
raise TypeError(
f"{type(arr).__name__} has no 'diff' method. "
"Convert to a suitable dtype prior to calling 'diff'."
)
arr = np.asarray(arr)
dtype = arr.dtype

is_timedelta = False
if needs_i8_conversion(arr.dtype):
Expand Down
13 changes: 0 additions & 13 deletions pandas/core/arraylike.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,19 +341,6 @@ def _reconstruct(result):

if result.ndim != self.ndim:
if method == "outer":
if self.ndim == 2:
# we already deprecated for Series
msg = (
"outer method for ufunc {} is not implemented on "
"pandas objects. Returning an ndarray, but in the "
"future this will raise a 'NotImplementedError'. "
"Consider explicitly converting the DataFrame "
"to an array with '.to_numpy()' first."
)
warnings.warn(
msg.format(ufunc), FutureWarning, stacklevel=find_stack_level()
)
return result
raise NotImplementedError
return result
if isinstance(result, BlockManager):
Expand Down
10 changes: 4 additions & 6 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -8999,12 +8999,9 @@ def ranker(data):
if numeric_only:
if self.ndim == 1 and not is_numeric_dtype(self.dtype):
# GH#47500
warnings.warn(
f"Calling Series.rank with numeric_only={numeric_only} and dtype "
f"{self.dtype} is deprecated and will raise a TypeError in a "
"future version of pandas",
category=FutureWarning,
stacklevel=find_stack_level(),
raise TypeError(
"Series.rank does not allow numeric_only=True with "
"non-numeric dtype."
)
data = self._get_numeric_data()
else:
Expand Down Expand Up @@ -10945,6 +10942,7 @@ def _stat_function(
FutureWarning,
stacklevel=find_stack_level(),
)

if axis is lib.no_default:
axis = None

Expand Down
13 changes: 3 additions & 10 deletions pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
cast,
overload,
)
import warnings
import weakref

import numpy as np
Expand Down Expand Up @@ -69,7 +68,6 @@
Substitution,
doc,
)
from pandas.util._exceptions import find_stack_level
from pandas.util._validators import (
validate_ascending,
validate_bool_kwarg,
Expand Down Expand Up @@ -4579,14 +4577,9 @@ def _reduce(
if name in ["any", "all"]:
Copy link
Member

@phofl phofl Nov 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove this? This raises in all cases

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the message is slightly different different

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah missed that, thanks

kwd_name = "bool_only"
# GH#47500 - change to TypeError to match other methods
warnings.warn(
f"Calling Series.{name} with {kwd_name}={numeric_only} and "
f"dtype {self.dtype} will raise a TypeError in the future",
FutureWarning,
stacklevel=find_stack_level(),
)
raise NotImplementedError(
f"Series.{name} does not implement {kwd_name}."
raise TypeError(
f"Series.{name} does not allow {kwd_name}={numeric_only} "
"with non-numeric dtypes."
)
with np.errstate(all="ignore"):
return op(delegate, skipna=skipna, **kwds)
Expand Down
21 changes: 9 additions & 12 deletions pandas/tests/arrays/categorical/test_algos.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,12 @@ def test_isin_empty(empty):


def test_diff():
s = pd.Series([1, 2, 3], dtype="category")
with tm.assert_produces_warning(FutureWarning):
result = s.diff()
expected = pd.Series([np.nan, 1, 1])
tm.assert_series_equal(result, expected)

expected = expected.to_frame(name="A")
df = s.to_frame(name="A")
with tm.assert_produces_warning(FutureWarning):
result = df.diff()

tm.assert_frame_equal(result, expected)
ser = pd.Series([1, 2, 3], dtype="category")

msg = "Convert to a suitable dtype"
with pytest.raises(TypeError, match=msg):
ser.diff()

df = ser.to_frame(name="A")
with pytest.raises(TypeError, match=msg):
df.diff()
1 change: 1 addition & 0 deletions pandas/tests/frame/test_reductions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1489,6 +1489,7 @@ def test_median_categorical_dtype_nuisance_column(self):
# TODO: np.median(df, axis=0) gives np.array([2.0, 2.0]) instead
# of expected.values

@pytest.mark.filterwarnings("ignore:.*will return a scalar.*:FutureWarning")
@pytest.mark.parametrize("method", ["min", "max"])
def test_min_max_categorical_dtype_non_ordered_nuisance_column(self, method):
# GH#28949 DataFrame.min should behave like Series.min
Expand Down
5 changes: 3 additions & 2 deletions pandas/tests/frame/test_ufunc.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,10 @@ def test_unary_accumulate_axis():
tm.assert_frame_equal(result, expected)


def test_frame_outer_deprecated():
def test_frame_outer_disallowed():
df = pd.DataFrame({"A": [1, 2]})
with tm.assert_produces_warning(FutureWarning):
with pytest.raises(NotImplementedError, match=""):
# deprecation enforced in 2.0
np.subtract.outer(df, df)


Expand Down
6 changes: 4 additions & 2 deletions pandas/tests/groupby/test_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -1528,8 +1528,10 @@ def test_deprecate_numeric_only_series(dtype, groupby_func, request):
err_category = TypeError
err_msg = f"{groupby_func} is not supported for object dtype"
elif groupby_func == "skew":
warn_category = FutureWarning
warn_msg = "will raise a TypeError in the future"
warn_category = None
warn_msg = ""
err_category = TypeError
err_msg = "Series.skew does not allow numeric_only=True with non-numeric"
else:
warn_category = FutureWarning
warn_msg = "This will raise a TypeError"
Expand Down
6 changes: 3 additions & 3 deletions pandas/tests/groupby/transform/test_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,9 +495,9 @@ def test_transform_coercion():

expected = g.transform(np.mean)

msg = "will return a scalar mean"
with tm.assert_produces_warning(FutureWarning, match=msg, check_stacklevel=False):
result = g.transform(lambda x: np.mean(x))
# in 2.0 np.mean on a DataFrame is equivalent to frame.mean(axis=None)
# which not gives a scalar instead of Series
result = g.transform(lambda x: np.mean(x))
tm.assert_frame_equal(result, expected)

with tm.assert_produces_warning(None):
Expand Down
15 changes: 3 additions & 12 deletions pandas/tests/series/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,18 +275,9 @@ def test_numeric_only(self, kernel, has_numeric_only, dtype):
with pytest.raises(TypeError, match=msg):
method(*args, numeric_only=True)
elif dtype is object:
if kernel == "rank":
msg = "Calling Series.rank with numeric_only=True and dtype object"
with tm.assert_produces_warning(FutureWarning, match=msg):
method(*args, numeric_only=True)
else:
warn_msg = (
f"Calling Series.{kernel} with numeric_only=True and dtype object"
)
err_msg = f"Series.{kernel} does not implement numeric_only"
with tm.assert_produces_warning(FutureWarning, match=warn_msg):
with pytest.raises(NotImplementedError, match=err_msg):
method(*args, numeric_only=True)
msg = f"Series.{kernel} does not allow numeric_only=True with non-numeric"
with pytest.raises(TypeError, match=msg):
method(*args, numeric_only=True)
else:
result = method(*args, numeric_only=True)
expected = method(*args, numeric_only=False)
Expand Down