【问题标题】:Pandas fails to aggregate with a list of aggregation functionsPandas 无法使用聚合函数列表进行聚合
【发布时间】:2019-02-26 17:04:12
【问题描述】:

如何指定自定义聚合函数,以便它们在pandas.DataFrame.aggregate 的列表参数中使用时表现正确?

给定 pandas 中的两列数据框 ...

import pandas as pd
import numpy as np
df = pd.DataFrame(index=range(10))
df['a'] = [ 3 * x for x in range(10) ]
df['b'] = [ 1 -2 * x for x in range(10) ]

...在聚合函数规范列表上进行聚合不是问题:

def ok_mean(x):
  return x.mean()

df.aggregate(['mean', np.max, ok_mean])
               a    b
mean        13.5    -8.0
amax        27.0    1.0
ok_mean     13.5    -8.0

但是当聚合被指定为(lambda 或命名的)函数时,聚合失败:

def nok_mean(x):
  return np.mean(x)

df.aggregate([lambda x:  np.mean(x), nok_mean])
                   a                 b
   <lambda> nok_mean <lambda> nok_mean
0   0.0      0.0     1.0     1.0
1   3.0      3.0    -1.0    -1.0
2   6.0      6.0    -3.0    -3.0
3   9.0      9.0    -5.0    -5.0
4   12.0    12.0    -7.0    -7.0
...

混合聚合和非聚合规范会导致错误:

df.aggregate(['mean', nok_mean])
~/anaconda3/envs/tsa37_jup/lib/python3.7/site-packages/pandas/core/base.py in _aggregate_multiple_funcs(self, arg, _level, _axis)
    607         # if we are empty
    608         if not len(results):
--> 609             raise ValueError("no results")
    610 

直接使用聚合函数(不在列表中)给出预期结果:

df.aggregate(nok_mean)
a    13.5
b    -8.0
dtype: float64

这是一个错误还是我在定义聚合函数的方式上遗漏了什么?在我的真实项目中,我使用了更复杂的聚合函数(例如this percentile one)。所以我的问题是:

如何指定自定义聚合函数以解决此错误?

请注意,在滚动、扩展或分组窗口上使用自定义聚合函数会产生预期的结果:

df.expanding().aggregate(['mean', nok_mean])
## returns cumulative aggregation results as expected

熊猫版本:0.23.4

【问题讨论】:

    标签: python pandas aggregate


    【解决方案1】:

    我发现使用非系列参数调用聚合函数时失败是一种解决方法:

    def ok_mean(x):
      return np.mean(x.values)
    
    def ok_mean2(x):
      if not isinstance(x,pd.Series):
        raise ValueError('need Series argument')
      return np.mean(x)
    
    df.aggregate(['mean', ok_mean, ok_mean2])
    

    似乎在这种情况下(在pandas.DataFrame.aggregate 的列表参数中),pandas 首先尝试将聚合函数应用于每个数据点,并且从失败的那一刻起,返回到正确的行为(使用 Series 回调进行汇总)。

    使用装饰器强制系列参数:

    def assert_argtype(clazz):
        def wrapping(f):
            def wrapper(s):
                if not isinstance(s,clazz):
                    raise ValueError('needs %s argument' % clazz)
                return f(s)
            return wrapper
        return wrapping
    
    @assert_argtype(pd.Series)
    def nok_mean(x):
        return np.mean(x)
    
    df.aggregate([nok_mean])
    ## OK now, decorator fixed it!
    

    【讨论】:

    【解决方案2】:

    根据这个问题的答案Pandas - DataFrame aggregate behaving oddly

    看起来这是因为您直接在单个值上调用 np.mean,而不是在数据框中的整个系列上调用。将函数更改为

    def nok_mean(x):
        return x.mean()
    

    现在允许您应用多个功能:

    df.agg(['mean', nok_mean])
    

    返回

                 a    b
    mean      13.5 -8.0
    nok_mean  13.5 -8.0
    

    【讨论】:

    • 我提炼了这个问题以澄清核心问题:我如何指定在这种情况下正常工作的自定义函数。我的示例表明我知道标准 pandas.DataFrame.mean 行为正确。但是,为什么知道通常这个聚合函数确实有效(非列表参数,在窗口上下文中)?实际上,我需要比平均值更复杂的聚合函数。
    • 您能否举一个您正在尝试执行的“更复杂的聚合”的示例?以及一些开始数据和预期输出。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-24
    • 2012-06-12
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-12
    相关资源
    最近更新 更多