@@ -735,6 +735,17 @@ def _selection_name(self):
735
735
min max
736
736
1 1 2
737
737
2 3 4
738
+
739
+ The output column names can be controlled by passing
740
+ the desired column names and aggregations as keyword arguments.
741
+
742
+ >>> s.groupby([1, 1, 2, 2]).agg(
743
+ ... minimum='min',
744
+ ... maximum='max',
745
+ ... )
746
+ minimum maximum
747
+ 1 1 2
748
+ 2 3 4
738
749
""" )
739
750
740
751
@Appender (_apply_docs ['template' ]
@@ -749,8 +760,24 @@ def apply(self, func, *args, **kwargs):
749
760
klass = 'Series' ,
750
761
axis = '' )
751
762
@Appender (_shared_docs ['aggregate' ])
752
- def aggregate (self , func_or_funcs , * args , ** kwargs ):
763
+ def aggregate (self , func_or_funcs = None , * args , ** kwargs ):
753
764
_level = kwargs .pop ('_level' , None )
765
+
766
+ relabeling = func_or_funcs is None
767
+ columns = None
768
+ no_arg_message = ("Must provide 'func_or_funcs' or named "
769
+ "aggregation **kwargs." )
770
+ if relabeling :
771
+ columns = list (kwargs )
772
+ if not PY36 :
773
+ # sort for 3.5 and earlier
774
+ columns = list (sorted (columns ))
775
+
776
+ func_or_funcs = [kwargs [col ] for col in columns ]
777
+ kwargs = {}
778
+ if not columns :
779
+ raise TypeError (no_arg_message )
780
+
754
781
if isinstance (func_or_funcs , str ):
755
782
return getattr (self , func_or_funcs )(* args , ** kwargs )
756
783
@@ -759,6 +786,8 @@ def aggregate(self, func_or_funcs, *args, **kwargs):
759
786
# but not the class list / tuple itself.
760
787
ret = self ._aggregate_multiple_funcs (func_or_funcs ,
761
788
(_level or 0 ) + 1 )
789
+ if relabeling :
790
+ ret .columns = columns
762
791
else :
763
792
cyfunc = self ._is_cython_func (func_or_funcs )
764
793
if cyfunc and not args and not kwargs :
@@ -793,11 +822,14 @@ def _aggregate_multiple_funcs(self, arg, _level):
793
822
# have not shown a higher level one
794
823
# GH 15931
795
824
if isinstance (self ._selected_obj , Series ) and _level <= 1 :
796
- warnings .warn (
797
- ("using a dict on a Series for aggregation\n "
798
- "is deprecated and will be removed in a future "
799
- "version" ),
800
- FutureWarning , stacklevel = 3 )
825
+ msg = dedent ("""\
826
+ using a dict on a Series for aggregation
827
+ is deprecated and will be removed in a future version. Use \
828
+ named aggregation instead.
829
+
830
+ >>> grouper.agg(name_1=func_1, name_2=func_2)
831
+ """ )
832
+ warnings .warn (msg , FutureWarning , stacklevel = 3 )
801
833
802
834
columns = list (arg .keys ())
803
835
arg = arg .items ()
@@ -1562,7 +1594,7 @@ def groupby_series(obj, col=None):
1562
1594
1563
1595
def _is_multi_agg_with_relabel (** kwargs ):
1564
1596
"""
1565
- Check whether the kwargs pass to .agg look like multi-agg with relabling .
1597
+ Check whether kwargs passed to .agg look like multi-agg with relabeling .
1566
1598
1567
1599
Parameters
1568
1600
----------
0 commit comments