我正在使用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
答案 0 :(得分:1)
您真的是说count
(非NaN值的数量)吗?不能仅从sum
和mean
推论得出。
我怀疑您要寻找的是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似乎已经解决了该问题。那既快速又简单-大熊猫的内部结构以及它们在瑞士军刀上已经拥有的所有工具给我留下了深刻的印象!