Skip to content

Commit 455ffb2

Browse files
authored
DEPR: pinning name in SeriesGroupBy.agg (#51703)
1 parent 56508fb commit 455ffb2

File tree

4 files changed

+31
-2
lines changed

4 files changed

+31
-2
lines changed

doc/source/whatsnew/v2.1.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ Other API changes
9393
Deprecations
9494
~~~~~~~~~~~~
9595
- Deprecated accepting slices in :meth:`DataFrame.take`, call ``obj[slicer]`` or pass a sequence of integers instead (:issue:`51539`)
96+
- Deprecating pinning ``group.name`` to each group in :meth:`SeriesGroupBy.aggregate` aggregations; if your operation requires utilizing the groupby keys, iterate over the groupby object instead (:issue:`41090`)
9697
-
9798

9899
.. ---------------------------------------------------------------------------

pandas/core/groupby/generic.py

+17
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
Union,
2424
cast,
2525
)
26+
import warnings
2627

2728
import numpy as np
2829

@@ -49,6 +50,7 @@
4950
Substitution,
5051
doc,
5152
)
53+
from pandas.util._exceptions import find_stack_level
5254

5355
from pandas.core.dtypes.common import (
5456
ensure_int64,
@@ -270,6 +272,16 @@ def aggregate(self, func=None, *args, engine=None, engine_kwargs=None, **kwargs)
270272
# pinned in _python_agg_general, only in _aggregate_named
271273
result = self._aggregate_named(func, *args, **kwargs)
272274

275+
warnings.warn(
276+
"Pinning the groupby key to each group in "
277+
f"{type(self).__name__}.agg is deprecated, and cases that "
278+
"relied on it will raise in a future version. "
279+
"If your operation requires utilizing the groupby keys, "
280+
"iterate over the groupby object instead.",
281+
FutureWarning,
282+
stacklevel=find_stack_level(),
283+
)
284+
273285
# result is a dict whose keys are the elements of result_index
274286
result = Series(result, index=self.grouper.result_index)
275287
result = self._wrap_aggregated_output(result)
@@ -407,6 +419,7 @@ def _aggregate_named(self, func, *args, **kwargs):
407419
for name, group in self.grouper.get_iterator(
408420
self._selected_obj, axis=self.axis
409421
):
422+
# needed for pandas/tests/groupby/test_groupby.py::test_basic_aggregations
410423
object.__setattr__(group, "name", name)
411424

412425
output = func(group, *args, **kwargs)
@@ -1537,6 +1550,7 @@ def _transform_general(self, func, *args, **kwargs):
15371550
except StopIteration:
15381551
pass
15391552
else:
1553+
# 2023-02-27 No tests broken by disabling this pinning
15401554
object.__setattr__(group, "name", name)
15411555
try:
15421556
path, res = self._choose_path(fast_path, slow_path, group)
@@ -1552,6 +1566,7 @@ def _transform_general(self, func, *args, **kwargs):
15521566
for name, group in gen:
15531567
if group.size == 0:
15541568
continue
1569+
# 2023-02-27 No tests broken by disabling this pinning
15551570
object.__setattr__(group, "name", name)
15561571
res = path(group)
15571572

@@ -1721,6 +1736,8 @@ def filter(self, func, dropna: bool = True, *args, **kwargs):
17211736
gen = self.grouper.get_iterator(obj, axis=self.axis)
17221737

17231738
for name, group in gen:
1739+
# 2023-02-27 no tests are broken this pinning, but it is documented in the
1740+
# docstring above.
17241741
object.__setattr__(group, "name", name)
17251742

17261743
res = func(group, *args, **kwargs)

pandas/core/groupby/ops.py

+5
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,11 @@ def apply_groupwise(
760760
zipped = zip(group_keys, splitter)
761761

762762
for key, group in zipped:
763+
# Pinning name is needed for
764+
# test_group_apply_once_per_group,
765+
# test_inconsistent_return_type, test_set_group_name,
766+
# test_group_name_available_in_inference_pass,
767+
# test_groupby_multi_timezone
763768
object.__setattr__(group, "name", key)
764769

765770
# group might be modified

pandas/tests/groupby/test_groupby.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def test_groupby_std_datetimelike():
6565

6666

6767
@pytest.mark.parametrize("dtype", ["int64", "int32", "float64", "float32"])
68-
def test_basic(dtype):
68+
def test_basic_aggregations(dtype):
6969
data = Series(np.arange(9) // 3, index=np.arange(9), dtype=dtype)
7070

7171
index = np.arange(9)
@@ -102,7 +102,13 @@ def test_basic(dtype):
102102
grouped.aggregate({"one": np.mean, "two": np.std})
103103

104104
group_constants = {0: 10, 1: 20, 2: 30}
105-
agged = grouped.agg(lambda x: group_constants[x.name] + x.mean())
105+
msg = (
106+
"Pinning the groupby key to each group in SeriesGroupBy.agg is deprecated, "
107+
"and cases that relied on it will raise in a future version"
108+
)
109+
with tm.assert_produces_warning(FutureWarning, match=msg):
110+
# GH#41090
111+
agged = grouped.agg(lambda x: group_constants[x.name] + x.mean())
106112
assert agged[1] == 21
107113

108114
# corner cases

0 commit comments

Comments
 (0)