Skip to content

Commit 6ad8655

Browse files
rhshadrachtopper-123
authored andcommitted
DEPR: Passing a dictionary to SeriesGroupBy.agg (pandas-dev#52268)
* DEPR: Passing a dictionary to SeriesGroupBy.agg * fixup * Remove dict, fixup * fixup frame docstring
1 parent 8169b6b commit 6ad8655

File tree

6 files changed

+120
-16
lines changed

6 files changed

+120
-16
lines changed

doc/source/whatsnew/v2.1.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ Deprecations
122122
- Deprecated 'method', 'limit', and 'fill_axis' keywords in :meth:`DataFrame.align` and :meth:`Series.align`, explicitly call ``fillna`` on the alignment results instead (:issue:`51856`)
123123
- Deprecated 'broadcast_axis' keyword in :meth:`Series.align` and :meth:`DataFrame.align`, upcast before calling ``align`` with ``left = DataFrame({col: left for col in right.columns}, index=right.index)`` (:issue:`51856`)
124124
- Deprecated the 'axis' keyword in :meth:`.GroupBy.idxmax`, :meth:`.GroupBy.idxmin`, :meth:`.GroupBy.fillna`, :meth:`.GroupBy.take`, :meth:`.GroupBy.skew`, :meth:`.GroupBy.rank`, :meth:`.GroupBy.cumprod`, :meth:`.GroupBy.cumsum`, :meth:`.GroupBy.cummax`, :meth:`.GroupBy.cummin`, :meth:`.GroupBy.pct_change`, :meth:`GroupBy.diff`, :meth:`.GroupBy.shift`, and :meth:`DataFrameGroupBy.corrwith`; for ``axis=1`` operate on the underlying :class:`DataFrame` instead (:issue:`50405`, :issue:`51046`)
125+
- Deprecated passing a dictionary to :meth:`.SeriesGroupBy.agg`; pass a list of aggregations instead (:issue:`50684`)
125126
- Deprecated logical operations (``|``, ``&``, ``^``) between pandas objects and dtype-less sequences (e.g. ``list``, ``tuple``), wrap a sequence in a :class:`Series` or numpy array before operating instead (:issue:`51521`)
126127
- Deprecated :meth:`DataFrame.swapaxes` and :meth:`Series.swapaxes`, use :meth:`DataFrame.transpose` or :meth:`Series.transpose` instead (:issue:`51946`)
127128
- Deprecated making :meth:`Series.apply` return a :class:`DataFrame` when the passed-in callable returns a :class:`Series` object. In the future this will return a :class:`Series`.

pandas/core/groupby/generic.py

+14-3
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@
7070
from pandas.core.groupby.groupby import (
7171
GroupBy,
7272
GroupByPlot,
73-
_agg_template,
73+
_agg_template_frame,
74+
_agg_template_series,
7475
_apply_docs,
7576
_transform_template,
7677
)
@@ -216,7 +217,7 @@ def _get_data_to_aggregate(
216217
def apply(self, func, *args, **kwargs) -> Series:
217218
return super().apply(func, *args, **kwargs)
218219

219-
@doc(_agg_template, examples=_agg_examples_doc, klass="Series")
220+
@doc(_agg_template_series, examples=_agg_examples_doc, klass="Series")
220221
def aggregate(self, func=None, *args, engine=None, engine_kwargs=None, **kwargs):
221222
if maybe_use_numba(engine):
222223
return self._aggregate_with_numba(
@@ -308,6 +309,16 @@ def _aggregate_multiple_funcs(self, arg, *args, **kwargs) -> DataFrame:
308309
raise SpecificationError("nested renamer is not supported")
309310
else:
310311
# GH#50684 - This accidentally worked in 1.x
312+
msg = (
313+
"Passing a dictionary to SeriesGroupBy.agg is deprecated "
314+
"and will raise in a future version of pandas. Pass a list "
315+
"of aggregations instead."
316+
)
317+
warnings.warn(
318+
message=msg,
319+
category=FutureWarning,
320+
stacklevel=find_stack_level(),
321+
)
311322
arg = list(arg.items())
312323
elif any(isinstance(x, (tuple, list)) for x in arg):
313324
arg = [(x, x) if not isinstance(x, (tuple, list)) else x for x in arg]
@@ -1293,7 +1304,7 @@ class DataFrameGroupBy(GroupBy[DataFrame]):
12931304
"""
12941305
)
12951306

1296-
@doc(_agg_template, examples=_agg_examples_doc, klass="DataFrame")
1307+
@doc(_agg_template_frame, examples=_agg_examples_doc, klass="DataFrame")
12971308
def aggregate(self, func=None, *args, engine=None, engine_kwargs=None, **kwargs):
12981309
if maybe_use_numba(engine):
12991310
return self._aggregate_with_numba(

pandas/core/groupby/groupby.py

+97-10
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ class providing the base-class of operations.
489489
--------
490490
%(example)s"""
491491

492-
_agg_template = """
492+
_agg_template_series = """
493493
Aggregate using one or more operations over the specified axis.
494494
495495
Parameters
@@ -503,23 +503,110 @@ class providing the base-class of operations.
503503
- function
504504
- string function name
505505
- list of functions and/or function names, e.g. ``[np.sum, 'mean']``
506-
- dict of axis labels -> functions, function names or list of such.
507506
- None, in which case ``**kwargs`` are used with Named Aggregation. Here the
508507
output has one column for each element in ``**kwargs``. The name of the
509508
column is keyword, whereas the value determines the aggregation used to compute
510509
the values in the column.
511510
512-
Can also accept a Numba JIT function with
513-
``engine='numba'`` specified. Only passing a single function is supported
514-
with this engine.
511+
.. versionchanged:: 1.1.0
515512
516-
If the ``'numba'`` engine is chosen, the function must be
517-
a user defined function with ``values`` and ``index`` as the
518-
first and second arguments respectively in the function signature.
519-
Each group's index will be passed to the user defined function
520-
and optionally available for use.
513+
Can also accept a Numba JIT function with
514+
``engine='numba'`` specified. Only passing a single function is supported
515+
with this engine.
516+
517+
If the ``'numba'`` engine is chosen, the function must be
518+
a user defined function with ``values`` and ``index`` as the
519+
first and second arguments respectively in the function signature.
520+
Each group's index will be passed to the user defined function
521+
and optionally available for use.
522+
523+
.. deprecated:: 2.1.0
524+
525+
Passing a dictionary is deprecated and will raise in a future version
526+
of pandas. Pass a list of aggregations instead.
527+
*args
528+
Positional arguments to pass to func.
529+
engine : str, default None
530+
* ``'cython'`` : Runs the function through C-extensions from cython.
531+
* ``'numba'`` : Runs the function through JIT compiled code from numba.
532+
* ``None`` : Defaults to ``'cython'`` or globally setting ``compute.use_numba``
533+
534+
.. versionadded:: 1.1.0
535+
engine_kwargs : dict, default None
536+
* For ``'cython'`` engine, there are no accepted ``engine_kwargs``
537+
* For ``'numba'`` engine, the engine can accept ``nopython``, ``nogil``
538+
and ``parallel`` dictionary keys. The values must either be ``True`` or
539+
``False``. The default ``engine_kwargs`` for the ``'numba'`` engine is
540+
``{{'nopython': True, 'nogil': False, 'parallel': False}}`` and will be
541+
applied to the function
542+
543+
.. versionadded:: 1.1.0
544+
**kwargs
545+
* If ``func`` is None, ``**kwargs`` are used to define the output names and
546+
aggregations via Named Aggregation. See ``func`` entry.
547+
* Otherwise, keyword arguments to be passed into func.
548+
549+
Returns
550+
-------
551+
{klass}
552+
553+
See Also
554+
--------
555+
{klass}.groupby.apply : Apply function func group-wise
556+
and combine the results together.
557+
{klass}.groupby.transform : Transforms the Series on each group
558+
based on the given function.
559+
{klass}.aggregate : Aggregate using one or more
560+
operations over the specified axis.
561+
562+
Notes
563+
-----
564+
When using ``engine='numba'``, there will be no "fall back" behavior internally.
565+
The group data and group index will be passed as numpy arrays to the JITed
566+
user defined function, and no alternative execution attempts will be tried.
567+
568+
Functions that mutate the passed object can produce unexpected
569+
behavior or errors and are not supported. See :ref:`gotchas.udf-mutation`
570+
for more details.
571+
572+
.. versionchanged:: 1.3.0
573+
574+
The resulting dtype will reflect the return value of the passed ``func``,
575+
see the examples below.
576+
{examples}"""
577+
578+
_agg_template_frame = """
579+
Aggregate using one or more operations over the specified axis.
580+
581+
Parameters
582+
----------
583+
func : function, str, list, dict or None
584+
Function to use for aggregating the data. If a function, must either
585+
work when passed a {klass} or when passed to {klass}.apply.
586+
587+
Accepted combinations are:
588+
589+
- function
590+
- string function name
591+
- list of functions and/or function names, e.g. ``[np.sum, 'mean']``
592+
- dict of axis labels -> functions, function names or list of such.
593+
- None, in which case ``**kwargs`` are used with Named Aggregation. Here the
594+
output has one column for each element in ``**kwargs``. The name of the
595+
column is keyword, whereas the value determines the aggregation used to compute
596+
the values in the column.
521597
522598
.. versionchanged:: 1.1.0
599+
600+
Can also accept a Numba JIT function with
601+
``engine='numba'`` specified. Only passing a single function is supported
602+
with this engine.
603+
604+
If the ``'numba'`` engine is chosen, the function must be
605+
a user defined function with ``values`` and ``index`` as the
606+
first and second arguments respectively in the function signature.
607+
Each group's index will be passed to the user defined function
608+
and optionally available for use.
609+
523610
*args
524611
Positional arguments to pass to func.
525612
engine : str, default None

pandas/tests/groupby/test_groupby.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,9 @@ def test_groupby_as_index_agg(df):
727727

728728
expected3 = grouped["C"].sum()
729729
expected3 = DataFrame(expected3).rename(columns={"C": "Q"})
730-
result3 = grouped["C"].agg({"Q": np.sum})
730+
msg = "Passing a dictionary to SeriesGroupBy.agg is deprecated"
731+
with tm.assert_produces_warning(FutureWarning, match=msg):
732+
result3 = grouped["C"].agg({"Q": np.sum})
731733
tm.assert_frame_equal(result3, expected3)
732734

733735
# GH7115 & GH8112 & GH8582

pandas/tests/groupby/test_grouping.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,9 @@ def test_multifunc_select_col_integer_cols(self, df):
486486
df.columns = np.arange(len(df.columns))
487487

488488
# it works!
489-
df.groupby(1, as_index=False)[2].agg({"Q": np.mean})
489+
msg = "Passing a dictionary to SeriesGroupBy.agg is deprecated"
490+
with tm.assert_produces_warning(FutureWarning, match=msg):
491+
df.groupby(1, as_index=False)[2].agg({"Q": np.mean})
490492

491493
def test_multiindex_columns_empty_level(self):
492494
lst = [["count", "values"], ["to filter", ""]]

scripts/validate_unwanted_patterns.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
"_new_Index",
3535
"_new_PeriodIndex",
3636
"_doc_template",
37-
"_agg_template",
37+
"_agg_template_series",
38+
"_agg_template_frame",
3839
"_pipe_template",
3940
"__main__",
4041
"_transform_template",

0 commit comments

Comments
 (0)