在pandas中对转换应用多个函数

7
在使用groupby后,当使用agg时,如果传递了一个columns:functions的字典,则函数将应用于相应的列。然而,这种语法在使用transform时不起作用。是否有另一种方法可以在transform中应用多个函数?
让我们举个例子:
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
3个回答

7

您仍然可以使用字典,只需进行一些小调整即可:

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包含多个列,解决方案是什么? - datapug

5
我认为现在(pandas 0.20.2)的函数 transform 没有使用类似于 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

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