Skip to content

CLN: Enforce deprecation of Series.agg using Series.apply #57332

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
Feb 10, 2024
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
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 @@ -119,6 +119,7 @@ Removal of prior version deprecations/changes
- Removed ``pandas.value_counts``, use :meth:`Series.value_counts` instead (:issue:`53493`)
- Removed ``read_gbq`` and ``DataFrame.to_gbq``. Use ``pandas_gbq.read_gbq`` and ``pandas_gbq.to_gbq`` instead https://pandas-gbq.readthedocs.io/en/latest/api.html (:issue:`55525`)
- Removed deprecated argument ``obj`` in :meth:`.DataFrameGroupBy.get_group` and :meth:`.SeriesGroupBy.get_group` (:issue:`53545`)
- Removed deprecated behavior of :meth:`Series.agg` using :meth:`Series.apply` (:issue:`53325`)
- Removed the ``ArrayManager`` (:issue:`55043`)
- Removed the ``fastpath`` argument from the :class:`Series` constructor (:issue:`55466`)
- Removed the ``is_boolean``, ``is_integer``, ``is_floating``, ``holds_integer``, ``is_numeric``, ``is_categorical``, ``is_object``, and ``is_interval`` attributes of :class:`Index` (:issue:`50042`)
Expand Down
17 changes: 1 addition & 16 deletions pandas/core/apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -1430,22 +1430,7 @@ def agg(self):
func = self.func
# string, list-like, and dict-like are entirely handled in super
assert callable(func)

# GH53325: The setup below is just to keep current behavior while emitting a
# deprecation message. In the future this will all be replaced with a simple
# `result = f(self.obj, *self.args, **self.kwargs)`.
try:
result = obj.apply(func, args=self.args, **self.kwargs)
except (ValueError, AttributeError, TypeError):
result = func(obj, *self.args, **self.kwargs)
else:
msg = (
f"using {func} in {type(obj).__name__}.agg cannot aggregate and "
f"has been deprecated. Use {type(obj).__name__}.transform to "
f"keep behavior unchanged."
)
warnings.warn(msg, FutureWarning, stacklevel=find_stack_level())

result = func(obj, *self.args, **self.kwargs)
return result

def apply_empty_result(self) -> Series:
Expand Down
8 changes: 2 additions & 6 deletions pandas/tests/apply/test_frame_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -1688,18 +1688,14 @@ def foo2(x, b=2, c=0):
expected = df + 7
tm.assert_frame_equal(result, expected)

msg = "using .+ in Series.agg cannot aggregate and"

with tm.assert_produces_warning(FutureWarning, match=msg):
result = df.agg([foo1, foo2], 0, 3, c=4)
result = df.agg([foo1, foo2], 0, 3, c=4)
expected = DataFrame(
[[8, 8], [9, 9], [10, 10]], columns=[["x", "x"], ["foo1", "foo2"]]
)
tm.assert_frame_equal(result, expected)

# TODO: the result below is wrong, should be fixed (GH53325)
with tm.assert_produces_warning(FutureWarning, match=msg):
result = df.agg({"x": foo1}, 0, 3, c=4)
result = df.agg({"x": foo1}, 0, 3, c=4)
expected = DataFrame([2, 3, 4], columns=["x"])
tm.assert_frame_equal(result, expected)

Expand Down
53 changes: 18 additions & 35 deletions pandas/tests/apply/test_series_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,7 @@ def f(x, a=0, b=0, c=0):
return x + a + 10 * b + 100 * c

s = Series([1, 2])
msg = (
"in Series.agg cannot aggregate and has been deprecated. "
"Use Series.transform to keep behavior unchanged."
)
with tm.assert_produces_warning(FutureWarning, match=msg):
result = s.agg(f, 0, *args, **kwargs)
result = s.agg(f, 0, *args, **kwargs)
expected = s + increment
tm.assert_series_equal(result, expected)

Expand All @@ -124,13 +119,9 @@ def foo1(x, a=1, c=0):
def foo2(x, b=2, c=0):
return x + b + c

msg = "using .+ in Series.agg cannot aggregate and"
with tm.assert_produces_warning(FutureWarning, match=msg):
s.agg(foo1, 0, 3, c=4)
with tm.assert_produces_warning(FutureWarning, match=msg):
s.agg([foo1, foo2], 0, 3, c=4)
with tm.assert_produces_warning(FutureWarning, match=msg):
s.agg({"a": foo1, "b": foo2}, 0, 3, c=4)
s.agg(foo1, 0, 3, c=4)
s.agg([foo1, foo2], 0, 3, c=4)
s.agg({"a": foo1, "b": foo2}, 0, 3, c=4)


def test_series_apply_map_box_timestamps(by_row):
Expand Down Expand Up @@ -410,34 +401,26 @@ def test_apply_map_evaluate_lambdas_the_same(string_series, func, by_row):

def test_agg_evaluate_lambdas(string_series):
# GH53325
# in the future, the result will be a Series class.

with tm.assert_produces_warning(FutureWarning):
result = string_series.agg(lambda x: type(x))
assert isinstance(result, Series) and len(result) == len(string_series)
result = string_series.agg(lambda x: type(x))
assert result is Series

with tm.assert_produces_warning(FutureWarning):
result = string_series.agg(type)
assert isinstance(result, Series) and len(result) == len(string_series)
result = string_series.agg(type)
assert result is Series


@pytest.mark.parametrize("op_name", ["agg", "apply"])
def test_with_nested_series(datetime_series, op_name):
# GH 2316
# GH 2316 & GH52123
# .agg with a reducer and a transform, what to do
msg = "cannot aggregate"
warning = FutureWarning if op_name == "agg" else None
with tm.assert_produces_warning(warning, match=msg):
# GH52123
result = getattr(datetime_series, op_name)(
lambda x: Series([x, x**2], index=["x", "x^2"])
)
expected = DataFrame({"x": datetime_series, "x^2": datetime_series**2})
tm.assert_frame_equal(result, expected)

with tm.assert_produces_warning(FutureWarning, match=msg):
result = datetime_series.agg(lambda x: Series([x, x**2], index=["x", "x^2"]))
tm.assert_frame_equal(result, expected)
result = getattr(datetime_series, op_name)(
lambda x: Series([x, x**2], index=["x", "x^2"])
)
if op_name == "apply":
expected = DataFrame({"x": datetime_series, "x^2": datetime_series**2})
tm.assert_frame_equal(result, expected)
else:
expected = Series([datetime_series, datetime_series**2], index=["x", "x^2"])
tm.assert_series_equal(result, expected)


def test_replicate_describe(string_series):
Expand Down