200

是否有 pandas 内置方法可以将两个不同的聚合函数f1, f2应用于同一列df["returns"],而无需agg()多次调用?

示例数据框:

import pandas as pd
import datetime as dt
import numpy as np

pd.np.random.seed(0)
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)
}) 

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

# Assume `f1` and `f2` are defined for aggregating.
df.groupby("dummy").agg({"returns": f1, "returns": f2})

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

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

4

3 回答 3

240

您可以简单地将函数作为列表传递:

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

或作为字典:

In [21]: df.groupby('dummy').agg({'returns':
                                  {'Mean': np.mean, 'Sum': np.sum}})
Out[21]: 
        returns          
           Mean       Sum
dummy                    
1      0.036901  0.369012

为了避免弃用警告:

df.groupby('dummy').agg(Mean=('returns', np.mean),
                        Sum=('returns', np.sum))
于 2012-11-27T20:57:33.097 回答
182

TLDR;Pandasgroupby.agg有一种新的、更简单的语法来指定 (1) 多列上的聚合,以及 (2) 列上的多个聚合。因此,要为pandas >= 0.25执行此操作,请使用

df.groupby('dummy').agg(Mean=('returns', 'mean'), Sum=('returns', 'sum'))

           Mean       Sum
dummy                    
1      0.036901  0.369012

或者

df.groupby('dummy')['returns'].agg(Mean='mean', Sum='sum')

           Mean       Sum
dummy                    
1      0.036901  0.369012

Pandas >= 0.25:命名聚合

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

从文档中,

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

  • 关键字是输出列名
  • 这些值是元组,其第一个元素是要选择的列,第二个元素是要应用于该列的聚合。Pandas 为 pandas.NamedAgg 命名元组提供了 ['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

或者,您可以使用pd.NamedAgg(本质上是一个命名元组)使事情更加明确。

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

Series 更简单,只需将 aggfunc 传递给关键字参数即可。

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       

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

df.groupby('kind')['height'].agg(**{'max height': 'max', ...})

熊猫 < 0.25

在更新到 0.24 的 pandas 版本中,如果使用字典为聚合输出指定列名,您将获得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

在 v0.20 中不推荐使用字典重命名列。在更新版本的 pandas 上,这可以通过传递元组列表更简单地指定。如果以这种方式指定函数,则该列的所有函数都需要指定为 (name, function) 对的元组。

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

        returns          
            op1       op2
dummy                    
1      0.328953  0.032895

或者,

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

            op1       op2
dummy                    
1      0.328953  0.032895
于 2019-01-22T01:50:41.690 回答
7

像这样的工作:

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
于 2012-09-26T01:30:08.793 回答