使用pandas GroupBy.agg()对同一列进行多次聚合

ely*_*ely 95 python aggregate dataframe pandas pandas-groupby

给出以下(完全矫枉过正的)数据框示例

import pandas as pd
import datetime as dt
df = pd.DataFrame({
         "date"    :  [dt.date(2012, x, 1) for x in range(1, 11)], 
         "returns" :  0.05 * np.random.randn(10), 
         "dummy"   :  np.repeat(1, 10)
})
Run Code Online (Sandbox Code Playgroud)

是否存在将两个不同的聚合函数应用于同一列的现有内置方法,而无需agg多次调用?

语法上错误但直观正确的方法是:

# Assume `function1` and `function2` are defined for aggregating.
df.groupby("dummy").agg({"returns":function1, "returns":function2})
Run Code Online (Sandbox Code Playgroud)

显然,Python不允许重复键.是否还有其他表达输入的方式agg?也许一个元组列表[(column, function)]会更好,允许多个函数应用于同一列?但它似乎只接受一本字典.

除了定义一个仅应用其中的两个函数的辅助函数之外,还有一个解决方法吗?(无论如何,它如何与聚合一起工作?)

bmu*_*bmu 130

您只需将这些函数作为列表传递:

In [20]: df.groupby("dummy").agg({"returns": [np.mean, np.sum]})
Out[20]: 
        returns          
            sum      mean

dummy                    
1      0.285833  0.028583
Run Code Online (Sandbox Code Playgroud)

或者作为字典:

In [21]: df.groupby('dummy').agg({'returns':
                                  {'Mean': np.mean, 'Sum': np.sum}})
Out[21]: 
        returns          
            Sum      Mean
dummy                    
1      0.285833  0.028583
Run Code Online (Sandbox Code Playgroud)

  • @sparc_spread将多个函数作为列表传递[在pandas文档中有详细描述](http://pandas.pydata.org/pandas-docs/stable/groupby.html#applying-multiple-functions-at-once).在将来的pandas版本中,不推荐将多个函数重命名并作为字典传递.详情见[0.20更改日志](http://pandas.pydata.org/pandas-docs/version/0.20/whatsnew.html#deprecate-groupby-agg-with-a-dictionary-when-renaming),其中我也[在其他地方总结了SO](/sf/answers/3072798711/). (8认同)
  • 已经说过了,但是不推荐使用字典来重命名年龄的输出列。您可以改为指定元组列表。[请参阅此答案。](/sf/answers/3801011161/) (7认同)
  • 有没有办法指定结果列名? (4认同)
  • @Ben我认为您之后必须使用重命名。[Tom Augspurger的示例(请参见单元格25)](http://nbviewer.ipython.org/gist/TomAugspurger/6e052140eaa5fdb6e8c0) (3认同)

cs9*_*s95 38

大熊猫> = 0.25:命名汇总

熊猫已经改变了行为,GroupBy.agg转而使用更直观的语法来指定命名聚合。请参阅0.25文档部分中的增强功能以及相关的GitHub问题GH18366GH26512

从文档中

为了通过控制输出列名来支持特定于列的聚合,pandas接受特殊的语法GroupBy.agg(),称为“命名聚合”,其中

  • 关键字是输出列名称
  • 值是元组,其第一个元素是要选择的列,第二个元素是要应用于该列的聚合。Pandas为pandas.NamedAgg namedtuple提供了字段['column','aggfunc'],以使参数更清晰。通常,聚合可以是可调用的或字符串别名。

您现在可以通过关键字参数传递一个元组。元组遵循的格式(<colName>, <aggFunc>)

import pandas as pd

pd.__version__                                                                                                                            
# '0.25.0.dev0+840.g989f912ee'

# Setup
df = pd.DataFrame({'kind': ['cat', 'dog', 'cat', 'dog'],
                   'height': [9.1, 6.0, 9.5, 34.0],
                   'weight': [7.9, 7.5, 9.9, 198.0]
})

df.groupby('kind').agg(
    max_height=('height', 'max'), min_weight=('weight', 'min'),)

      max_height  min_weight
kind                        
cat          9.5         7.9
dog         34.0         7.5
Run Code Online (Sandbox Code Playgroud)

另外,您可以使用pd.NamedAgg(本质上是namedtuple)使事情更明确。

df.groupby('kind').agg(
    max_height=pd.NamedAgg(column='height', aggfunc='max'), 
    min_weight=pd.NamedAgg(column='weight', aggfunc='min')
)

      max_height  min_weight
kind                        
cat          9.5         7.9
dog         34.0         7.5
Run Code Online (Sandbox Code Playgroud)

对于Series来说甚至更简单,只需将aggfunc传递给关键字arguments.t即可。

df.groupby('kind')['height'].agg(max_height='max', min_height='min')    

      max_height  min_height
kind                        
cat          9.5         9.1
dog         34.0         6.0       
Run Code Online (Sandbox Code Playgroud)

最后,如果您的列名不是有效的python标识符,请使用带有解包功能的字典:

df.groupby('kind')['height'].agg(**{'max height': 'max', ...})
Run Code Online (Sandbox Code Playgroud)

熊猫<0.25

在最新版本的熊猫(最高可达0.24)中,如果使用字典为聚合输出指定列名,则会得到FutureWarning

df.groupby('dummy').agg({'returns': {'Mean': 'mean', 'Sum': 'sum'}})
# FutureWarning: using a dict with renaming is deprecated and will be removed 
# in a future version
Run Code Online (Sandbox Code Playgroud)

v0.20中不建议使用字典重命名列。在较新版本的熊猫上,可以通过传递元组列表来更简单地指定它。如果以这种方式指定函数,则该列的所有函数都必须指定为(名称,函数)对的元组。

df.groupby("dummy").agg({'returns': [('op1', 'sum'), ('op2', 'mean')]})

        returns          
            op1       op2
dummy                    
1      0.328953  0.032895
Run Code Online (Sandbox Code Playgroud)

要么,

df.groupby("dummy")['returns'].agg([('op1', 'sum'), ('op2', 'mean')])

            op1       op2
dummy                    
1      0.328953  0.032895
Run Code Online (Sandbox Code Playgroud)

  • 这应该是首要答案,因为使用新版本的界面使用了更清晰、更干净的解决方案。 (6认同)

Cha*_*She 6

会这样的工作:

In [7]: df.groupby('dummy').returns.agg({'func1' : lambda x: x.sum(), 'func2' : lambda x: x.prod()})
Out[7]: 
              func2     func1
dummy                        
1     -4.263768e-16 -0.188565
Run Code Online (Sandbox Code Playgroud)

  • 不,这不起作用。如果您查看`aggregate` 的文档字符串,它明确指出当传递`dict` 时,键必须是列名。因此,要么您的示例是您在未检查此错误的情况下输入的内容,要么 Pandas 在这里破坏了自己的文档。 (2认同)