多层级列的聚合分组

4
我是一名有用的助手,可以为您翻译文本。
我有一个分组的DataFrame,我想用一组函数对其进行聚合,这些函数应该映射到特定的列。对于单级列,可以使用groups.agg({'colname':<function>})轻松实现。但是,我无法处理多级列,我只想引用其中的一级。
下面是一个示例。
让我们创建一些样本数据:
import itertools
import pandas as pd

lev1 = ['foo', 'bar', 'baz']
lev2 = list('abc')

n = 6

df = pd.DataFrame({k: np.random.randn(n) for k in itertools.product(lev1,lev2)}, 
                  index=pd.DatetimeIndex(start='2015-01-01', periods=n, freq='11D'))

这看起来像:

             bar               baz               foo            
               a     b     c     a     b     c     a     b     c
2015-01-01 -1.11  2.12 -1.00  0.18  0.14  1.24  0.73  0.06  3.66
2015-01-12 -1.43  0.75  0.38  0.04 -0.33 -0.42  1.00 -1.63 -1.35
2015-01-23  0.01 -1.70 -1.39  0.59 -1.10 -1.17 -1.51 -0.54 -1.11
2015-02-03  0.93  0.70 -0.12  1.07 -0.97 -0.45 -0.19  0.11 -0.79
2015-02-14  0.30  0.49  0.60 -0.28 -0.38  1.11  0.15  0.78 -0.58
2015-02-25 -0.26  0.51  0.82  0.05 -1.45  0.14  0.53 -0.33 -1.35

使用以下方式按月分组:

groups = df.groupby(pd.TimeGrouper('MS'))

基于列中的顶级定义一些函数:

funcs = {'bar': np.sum, 'baz': np.mean, 'foo': np.min}

然而,执行groups.agg(funcs)会导致KeyError错误,因为它期望每个级别都有一个键,这是有道理的。

以下示例可以正常工作:

groups.agg({('bar', 'a'): np.mean})

                 bar
                   a
2015-01-01 -0.845554
2015-02-01  0.324897

但我不想在第二层指定每个键。因此,我正在寻找类似以下的解决方案:

groups.agg({('bar', slice(None)): np.mean})

但是这当然行不通,因为一个“slice”并不可哈希,因此不能放在字典里。
解决方法是:
def multifunc(group):

    func = funcs[group.name[0]]        
    return func(group)

groups.agg(multifunc)

但是这种写法不够易读,也不符合“Pandonic”的风格。而且它不允许在同一列上执行多个函数,就像agg函数那样。一定有更好/标准的方法来执行这样的任务,这并不是很罕见。


我打开了一个问题来讨论我们是否想要使这更容易:https://github.com/pydata/pandas/issues/9585 但是,我不确定什么是最好的接口。我想{'bar': np.sum, 'baz': np.mean, 'foo': np.min}可能会起作用?欢迎提出意见! - joris
谢谢Joris!看到关于这个问题的讨论肯定很有趣。总是有解决方法,就像Unutbu展示的那样。但这意味着要远离Pandas接口,易用的接口是使Pandas如此令人惊艳的重要组成部分。 - Rutger Kassies
1个回答

4

我认为这并没有什么捷径可言。幸运的是,显式构建所需的字典并不太难:

result = groups.agg(
    {(k1, k2): funcs[k1] for k1, k2 in itertools.product(lev1,lev2)})

import itertools
import numpy as np
import pandas as pd

lev1 = ['foo', 'bar', 'baz']
lev2 = list('abc')

n = 6

df = pd.DataFrame(
    {k: np.random.randn(n) for k in itertools.product(lev1,lev2)}, 
    index=pd.DatetimeIndex(start='2015-01-01', periods=n, freq='11D'))
groups = df.groupby(pd.TimeGrouper('MS'))
funcs = {'bar': np.sum, 'baz': np.mean, 'foo': np.min}
result = groups.agg(
    {(k1, k2): funcs[k1] for k1, k2 in itertools.product(lev1,lev2)})
result = result.sortlevel(axis=1)
print(result)

产出率
                 bar                           baz                      \
                   a         b         c         a         b         c   
2015-01-01 -2.144890  1.075044  1.038169 -0.460649 -0.309966 -0.211147   
2015-02-01  1.313744  0.247171  1.049129 -0.174827 -0.437982 -0.196427   

                 foo                      
                   a         b         c  
2015-01-01 -1.358973 -1.846916 -0.896234  
2015-02-01 -1.354953 -0.699607  0.288214  

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接