【问题标题】:applying several functions in transform in pandas在 pandas 的变换中应用几个函数
【发布时间】:2020-12-13 03:34:25
【问题描述】:

groupby之后,使用agg时,如果传入columns:functions的dict,则函数将应用到相应的列中。然而,这种语法不适用于transformtransform中的多个函数是否有其他方法可以应用?

举个例子:

import pandas as pd
df_test = pd.DataFrame([[1,2,3],[1,20,30],[2,30,50],[1,2,33],[2,4,50]],columns = ['a','b','c'])
Out[1]:
    a   b   c
0   1   2   3
1   1   20  30
2   2   30  50
3   1   2   33
4   2   4   50

def my_fct1(series):
    return series.mean()

def my_fct2(series):
    return series.std()

df_test.groupby('a').agg({'b':my_fct1,'c':my_fct2})

Out[2]:
    c   b
a       
1   16.522712   8
2   0.000000    17

前面的例子展示了如何对agg中的不同列应用不同的函数,但是如果我们想转换列而不聚合它们,agg就不能再使用了。因此:

df_test.groupby('a').transform({'b':np.cumsum,'c':np.cumprod})
Out[3]:
TypeError: unhashable type: 'dict'

我们如何使用以下预期输出执行这样的操作:

    a   b   c
0   1   2   3
1   1   22  90
2   2   30  50
3   1   24  2970
4   2   34  2500

【问题讨论】:

    标签: python pandas transformation


    【解决方案1】:

    你仍然可以使用字典,但需要一点技巧:

    df_test.groupby('a').transform(lambda x: {'b': x.cumsum(), 'c': x.cumprod()}[x.name])
    Out[427]: 
        b     c
    0   2     3
    1  22    90
    2  30    50
    3  24  2970
    4  34  2500
    

    如果需要保留a列,可以这样做:

    df_test.set_index('a')\
           .groupby('a')\
           .transform(lambda x: {'b': x.cumsum(), 'c': x.cumprod()}[x.name])\
           .reset_index()
    Out[429]: 
       a   b     c
    0  1   2     3
    1  1  22    90
    2  2  30    50
    3  1  24  2970
    4  2  34  2500
    

    另一种方法是使用 if else 来检查列名:

    df_test.set_index('a')\
           .groupby('a')\
           .transform(lambda x: x.cumsum() if x.name=='b' else x.cumprod())\
           .reset_index()
    

    【讨论】:

    • 如果 groupby 包含多于一列,会有什么解决方案?
    【解决方案2】:

    我认为现在 (pandas 0.20.2) 函数 transform 没有使用 dict 实现 - 列名称具有类似 agg 的函数。

    如果函数返回相同长度的Series

    df1 = df_test.set_index('a').groupby('a').agg({'b':np.cumsum,'c':np.cumprod}).reset_index()
    print (df1)
       a     c   b
    0  1     3   2
    1  1    90  22
    2  2    50  30
    3  1  2970  24
    4  2  2500  34
    

    但是如果聚合不同的长度需要join:

    df2 = df_test[['a']].join(df_test.groupby('a').agg({'b':my_fct1,'c':my_fct2}), on='a')
    print (df2)
       a          c   b
    0  1  16.522712   8
    1  1  16.522712   8
    2  2   0.000000  17
    3  1  16.522712   8
    4  2   0.000000  17
    

    【讨论】:

      【解决方案3】:

      随着对 Pandas 的更新,您可以使用 assign 方法和 transform 来追加新列,或用新值替换现有列:

      grouper = df_test.groupby("a")
      
      df_test.assign(b=grouper["b"].transform("cumsum"), 
                     c=grouper["c"].transform("cumprod"))
      
          a   b   c
      0   1   2   3
      1   1   22  90
      2   2   30  50
      3   1   24  2970
      4   2   34  2500
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-27
        • 2019-12-20
        • 2018-02-14
        • 2019-02-23
        相关资源
        最近更新 更多