我正在使用 Pandas v1.1.0 通过滚动计数、求和和均值运行 group,我注意到滚动计数比滚动均值和总和慢得多。这似乎违反直觉,因为我们可以从平均值和总和中得出计数并节省时间。这是一个错误还是我错过了什么?多谢指教。
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
Run Code Online (Sandbox Code Playgroud)
您真的是指count(非 NaN 值的数量)吗?这不能仅从sum和推断出来mean。
我怀疑您正在寻找的是一个size运算符(只是组的长度,无论是否存在任何 NaN)。虽然size存在于常规中groupby,但似乎在RollingGroupBy(至少从 pandas 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])
Run Code Online (Sandbox Code Playgroud)
当然,这两者都没有那么快,因为需要调用每个组的函数,而不是全部矢量化并仅在滚动窗口索引start和 的基础上工作end。rgb.sum()在我的系统上,上述任何一个都比或慢 2 倍rgb.mean()。
考虑如何实现size:这是显而易见的(仅end - start针对每个窗口)。
现在,如果确实想加快速度count(非 NaN 值的计数):可以首先建立一个“累积计数”:
cumcnt = (1 - df['column1'].isnull()).cumsum()
Run Code Online (Sandbox Code Playgroud)
(这非常快,比rgb.mean()我的系统快大约 200 倍)。
那么滚动函数就可以简单地采用cumcnt[end] - cumcnt[start].
RollingGroupBy我对内部结构(以及它们对各种s的使用)了解不够,无法mixin评估可行性,但至少在功能上它看起来相当简单。
更新:
这些提交似乎已经解决了这个问题。这既快速又简单——熊猫的内部结构以及它们瑞士军刀上已有的所有工具给我留下了深刻的印象!