我有一个很大的数据框,我按1到n列进行分组,并希望在两列(例如foo和bar)上对这些组应用函数。
以下是一个示例数据框:
foo_function = lambda x: np.sum(x.a+x.b)
df = pd.DataFrame({'a':[1,2,3,4,5,6],
'b':[1,2,3,4,5,6],
'c':['q', 'q', 'q', 'q', 'w', 'w'],
'd':['z','z','z','o','o','o']})
# works with apply, but I want transform:
df.groupby(['c', 'd'])[['a','b']].apply(foo_function)
# transform doesn't work!
df.groupby(['c', 'd'])[['a','b']].transform(foo_function)
TypeError: cannot concatenate a non-NDFrame object
但是transform
显然无法将多个列组合在一起,因为它会分别查看每个列(与apply不同)。在速度/优雅方面,下一个最佳选择是什么?例如我可以使用apply
,然后使用df['new_col']
创建pd.match
,但这有时需要匹配多个groupby列(col1和col2),这看起来非常hacky /需要相当多的代码。
- >是否有一个类似groupby()。变换的函数可以使用多个列的函数?如果这不存在,那么最好的黑客是什么?
答案 0 :(得分:10)
Circa Pandas版本0.18,看来原始答案(如下)不再有效。
相反,如果您需要跨多个列进行groupby计算,请先执行多列计算 ,然后执行groupby:
df = pd.DataFrame({'a':[1,2,3,4,5,6],
'b':[1,2,3,4,5,6],
'c':['q', 'q', 'q', 'q', 'w', 'w'],
'd':['z','z','z','o','o','o']})
df['e'] = df['a'] + df['b']
df['e'] = (df.groupby(['c', 'd'])['e'].transform('sum'))
print(df)
产量
a b c d e
0 1 1 q z 12
1 2 2 q z 12
2 3 3 q z 12
3 4 4 q o 8
4 5 5 w o 22
5 6 6 w o 22
原始答案:
错误消息:
TypeError: cannot concatenate a non-NDFrame object
建议为了连接,foo_function
应返回NDFrame(例如Series或DataFrame)。如果你返回一个系列,那么:
In [99]: df.groupby(['c', 'd']).transform(lambda x: pd.Series(np.sum(x['a']+x['b'])))
Out[99]:
a b
0 12 12
1 12 12
2 12 12
3 8 8
4 22 22
5 22 22
答案 1 :(得分:1)
我在阅读问题的过程中,您希望能够使用两列中的各个值执行任意操作。您只需要确保返回与传入的大小相同的数据框。我认为最好的方法是创建一个新列,如下所示:
df = pd.DataFrame({'a':[1,2,3,4,5,6],
'b':[1,2,3,4,5,6],
'c':['q', 'q', 'q', 'q', 'w', 'w'],
'd':['z','z','z','o','o','o']})
df['e']=0
def f(x):
y=(x['a']+x['b'])/sum(x['b'])
return pd.DataFrame({'e':y,'a':x['a'],'b':x['b']})
df.groupby(['c','d']).transform(f)
a b e
0 1 1 0.333333
1 2 2 0.666667
2 3 3 1.000000
3 4 4 2.000000
4 5 5 0.909091
5 6 6 1.090909
如果您的数据框非常复杂,可以选择列(例如df.groupby(['c'])['a','b','e'].transform(f)
)
这对我来说看起来非常不合适,但它在大型数据集上仍然比apply
快得多。
另一种方法是使用set_index
来捕获您需要的所有列,然后只将一列传递给transform
。