代码之家  ›  专栏  ›  技术社区  ›  Andy L.

DataFrameGroupby。agg NamedAgg在同一列上在自定义函数上出错,但在bult in函数上有效

  •  1
  • Andy L.  · 技术社区  · 5 年前

    安装程序

    np.random.seed(0)
    df = pd.DataFrame(zip([1, 1, 2, 2, 2, 3, 7, 7, 9, 10],
                          *np.random.randint(1, 100, 20).reshape(-1,10)),
                      columns=['A','B', 'C'])
    
    Out[127]:
        A   B   C
    0   1  45  71
    1   1  48  89
    2   2  65  89
    3   2  68  13
    4   2  68  59
    5   3  10  66
    6   7  84  40
    7   7  22  88
    8   9  37  47
    9  10  88  89
    
    f = lambda x: x.max()
    

    namedagon内置函数运行良好

    df.groupby('A').agg(B_min=('B', 'min'), B_max=('B', 'max'), C_max=('C', 'max'))
    
    Out[133]:
        B_min  B_max  C_max
    A
    1      45     48     89
    2      65     68     89
    3      10     10     66
    7      22     84     88
    9      37     37     47
    10     88     88     89
    

    自定义函数上的namedag f 出错

    df.groupby('A').agg(B_min=('B', 'min'), B_max=('B', f), C_max=('C', 'max'))
    
    KeyError: "[('B', '<lambda>')] not in index"
    

    这个错误有什么解释吗?这是故意的限制吗?

    0 回复  |  直到 5 年前
        1
  •  1
  •   ALollz    5 年前

    这个问题是因为 _mangle_lambda_list ,它会在某个时候被调用。似乎存在一种不匹配,即结果聚合被重命名,但输出列列表, ordered 然后使用 here ,不会改变。因为这个函数专门检查 if com.get_callable_name(aggfunc) == "<lambda>" 除了 '<lambda>' 将毫无问题地工作:

    样本数据

    import pandas as pd
    import numpy as np
    np.random.seed(0)
    df = pd.DataFrame(zip([1, 1, 2, 2, 2, 3, 7, 7, 9, 10],
                          *np.random.randint(1, 100, 20).reshape(-1,10)),
                      columns=['A','B', 'C'])
    f = lambda x: x.max()
    kwargs = {'B_min': ('B', 'min'), 'B_max':('B', f), 'C_max':('C', 'max')}
    

    下面是聚合时调用的最相关的主要步骤,我们可以看到KeyError的来源。

    func, columns, order = pd.core.groupby.generic._normalize_keyword_aggregation(kwargs)
    
    print(order)
    #[('B', 'min'), ('B', '<lambda>'), ('C', 'max')]
    
    func = pd.core.groupby.generic._maybe_mangle_lambdas(func)
    df.groupby('A')._aggregate(func)
    #     B              C
    #   min <lambda_0> max        # _0 ruins indexing with ('B', '<lambda>')
    #A                    
    #1   45         48  89
    #2   65         68  89
    #3   10         10  66
    #7   22         84  88
    #9   37         37  47
    #10  88         88  89
    

    因为 _mangle_lambda_列表 仅当同一列有多个聚合时才调用 可以 逍遥法外 “<lambda>' 名字,只要是 唯一的聚集 为了那个专栏。

    df.groupby('A').agg(A_min=('A', 'min'), B_max=('B', f))
    #    A_min  B_max
    #A               
    #1       1     48
    #2       2     68
    #3       3     10
    #7       7     84
    #9       9     37
    #10     10     88