Pandas v1.1.0:Groupby滚动计数慢于滚动平均值和总和

时间:2020-08-08 10:22:56

标签: python pandas

我正在使用Pandas v1.1.0运行groupby滚动计数,总和和均值,我注意到滚动计数比滚动均值和总和要慢得多。这似乎很不直观,因为我们可以从平均值和总和中得出计数并节省时间。这是错误还是我错过了什么?感谢您的建议。

import pandas as pd

# Generate sample df
df = pd.DataFrame({'column1': range(600), 'group': 5*['l'+str(i) for i in range(120)]})

# sort by group for easy/efficient joining of new columns to df
df=df.sort_values('group',kind='mergesort').reset_index(drop=True)

# timing of groupby rolling count, sum and mean
%timeit df['mean']=df.groupby('group').rolling(3,min_periods=1)['column1'].mean().values
%timeit df['sum']=df.groupby('group').rolling(3,min_periods=1)['column1'].sum().values
%timeit df['count']=df.groupby('group').rolling(3,min_periods=1)['column1'].count().values

### Output
6.14 ms ± 812 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
5.61 ms ± 179 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
76.1 ms ± 4.78 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

### df Output for illustration
print(df.head(10))

   column1 group   mean     sum  count
0        0    l0    0.0     0.0    1.0
1      120    l0   60.0   120.0    2.0
2      240    l0  120.0   360.0    3.0
3      360    l0  240.0   720.0    3.0
4      480    l0  360.0  1080.0    3.0
5        1    l1    1.0     1.0    1.0
6      121    l1   61.0   122.0    2.0
7      241    l1  121.0   363.0    3.0
8      361    l1  241.0   723.0    3.0
9      481    l1  361.0  1083.0    3.0

1 个答案:

答案 0 :(得分:1)

您真的是说count(非NaN值的数量)吗?不能仅从summean推论得出。

我怀疑您要寻找的是size运算符(无论组的长度如何,无论该NaN是否存在,都只是该组的长度)。尽管size中存在groupby,但RollingGroupBy中似乎不存在(至少从熊猫1.1.4开始)。可以使用以下方法计算滚动组的大小:

# DRY:
rgb = df.groupby('group').rolling(3, min_periods=1)['column1']

# size is either:
rgb.apply(len)

# or
rgb.apply(lambda g: g.shape[0])

当然,这两个都不是最快的,因为每个组都需要调用该函数,而不是全部矢量化并且仅在滚动窗口索引start下工作和end。在我的系统上,以上任何一项都比rgb.sum()rgb.mean()慢2倍。

考虑如何实现size:这很明显(每个窗口仅end - start

现在,在真的想要加快count(非NaN值的计数)的情况下:一个人可以首先建立“累积计数”:

cumcnt = (1 - df['column1'].isnull()).cumsum()

(这非常快,比我系统上的rgb.mean()快200倍)。

然后滚动功能可以简单地使用cumcnt[end] - cumcnt[start]

我对RollingGroupBy的内部知识(以及它们对各种mixin的使用)了解不够,以评估可行性,但至少在功能上似乎很简单。

更新

these commits似乎已经解决了该问题。那既快速又简单-大熊猫的内部结构以及它们在瑞士军刀上已经拥有的所有工具给我留下了深刻的印象!