熊猫AGG使用"中间"列而不重新计算[组大小]乘以相同的值



假设我有一个DataFramedf=pd.DataFrame({'a':[1,2,np.nan,3,4,5,3], 'b':[11,22,22,11,22,22,22]})

a   b
0  1.0  11
1  2.0  22
2  NaN  22
3  3.0  11
4  4.0  22
5  5.0  22
6  3.0  22

我想计算一个简化的数据帧,其中我按b分组,其中我的列取决于分组平均值。具体来说,我希望该列包含

a中小于分组平均值的元素数

为此,我找到了一个似乎可以改进的解决方案,因为我猜它重新计算了"11"组的平均值2次和"22"组的5次:

使用groupby、agg和NamedAgg的慢速解决方案

df.groupby('b').agg(c=pd.NamedAgg(column='a', aggfunc=lambda x: sum(i<x.mean() for i in x)))

dff=df.groupby('b').agg(c=pd.NamedAgg(column='a', aggfunc=lambda x: sum(i<x.mean() for i in x)))
print(dff)
c
b    
11  1
22  2

你知道一种更好的方法吗,每组只计算一次平均值?

我已经在pandasmerge、concat、join、agg、apply等中搜索了参数。但我认为必须有这些参数的巧妙组合才能实现我想要做的事情。

不要使用python的sum,使用矢量对应项,它将使您能够为每个组只计算一次平均值:

df.groupby('b')['a'].agg(c=lambda s: s.lt(s.mean()).sum())

输出:

c
b    
11  1
22  2

速度比较

## provided example
# vectorial approach
1.07 ms ± 33.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
# loop
2.86 ms ± 129 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

## 70k rows
# vectorial approach
3.19 ms ± 391 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# loop
7.67 s ± 104 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

根据我的经验,如果有一个大的数据集(数百万或更多的obs),那么使用merge比使用lambdatransform更高效、更快。

tem = df.groupby('b')['a'].mean().reset_index(name='mean')
df = pd.merge(df, tem, on='b', how='left')
df.loc[df['a']<df['mean']].groupby('b')['a'].count().reset_index(name='c')

最新更新