如何跨多列使用 groupby 转换

新手上路,请多包涵

我有一个大数据框,我按 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 然后创建 df['new_col'] 通过使用 pd.match ,但这似乎真的需要匹配 overcol1 和多个 groupby 列) / 需要相当多的代码。

–> 是否有类似于 groupby().transform 的函数可以使用处理多列的函数?如果这不存在,什么是最好的黑客?

原文由 Hillary Sanders 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 540
2 个回答

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

原文由 unutbu 发布,翻译遵循 CC BY-SA 3.0 许可协议

我阅读这个问题的方式是,您希望能够对两列中的各个值进行任意操作。您只需要确保返回一个与传入的大小相同的数据框。我认为最好的方法是创建一个新列,如下所示:

 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

原文由 Victor Chubukov 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题