我想将滚动函数应用于由两列重复日期条目分组的数据框。具体来说,将“freq”和“window”作为日期时间值,而不仅仅是整数。
原则上,我尝试将How to apply rolling functions in a group by object in pandas和pandas rolling sum of last five minutes中的方法结合起来。
输入
这是一个数据样本,其中一个id = 33,尽管我们期望有几个id。
X = [{'date': '2017-02-05', 'id': 33, 'item': 'A', 'points': 20},
{'date': '2017-02-05', 'id': 33, 'item': 'B', 'points': 10},
{'date': '2017-02-06', 'id': 33, 'item': 'B', 'points': 10},
{'date': '2017-02-11', 'id': 33, 'item': 'A', 'points': 1},
{'date': '2017-02-11', 'id': 33, 'item': 'A', 'points': 1},
{'date': '2017-02-11', 'id': 33, 'item': 'A', 'points': 1},
{'date': '2017-02-13', 'id': 33, 'item': 'A', 'points': 4}]
# df = pd.DataFrame(X) and reindex df to pd.to_datetime(df['date'])
df
id item points
date
2017-02-05 33 A 20
2017-02-05 33 B 10
2017-02-06 33 B 10
2017-02-11 33 A 1
2017-02-11 33 A 1
2017-02-11 33 A 1
2017-02-13 33 A 4
目标
每2天对每个'id'进行一次采样(freq ='2d')并返回前三天每个项目的总积分总和(window ='3D'),包括结束日期
所需输出
id A B
date
2017-02-05 33 20 10
2017-02-07 33 20 30
2017-02-09 33 0 10
2017-02-11 33 3 0
2017-02-13 33 7 0
E.g。在包含权利的结束日期2017-02-13中,我们将2017-02-11的3天期间样本计算到2017-02-13。在此期间,id = 33的A点的总和等于1 + 1 + 1 + 4 = 7
尝试
由于重复日期,尝试使用pd.rolling_sum的groupby不起作用
df.groupby(['id', 'item'])['points'].apply(pd.rolling_sum, freq='4D', window=3)
ValueError: cannot reindex from a duplicate axis
另请注意,文档http://pandas.pydata.org/pandas-docs/version/0.17.0/generated/pandas.rolling_apply.html'window'是一个表示样本周期大小的int,而不是样本的天数。
我们也可以尝试重新取样并使用最后一次,但是似乎没有使用3天所需的回顾
df.groupby(['id', 'item'])['points'].resample('2D', label='right', closed='right').\
apply(lambda x: x.last('3D').sum())
id item date
33 A 2017-02-05 20
2017-02-07 0
2017-02-09 0
2017-02-11 3
2017-02-13 4
B 2017-02-05 10
2017-02-07 10
当然,在唯一id的ID上设置一个循环,选择df_id = df [df ['id'] == ID],并对这些句点求和确实有效,但计算密集,并且不利用groupby的好处向量化。
感谢@jezrael目前提出的好建议
备注
Pandas版本= 0.20.1
关于为什么滚动()的文档在这里我有点困惑:https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.rolling.html
建议“window”参数可以是int或offset但是在尝试df.rolling时(window ='3D',...)我得到raise ValueError("window must be an integer")
看来上面的文档与./core/window.py中滚动窗口的最新代码不一致:
https://github.com/pandas-dev/pandas/blob/master/pandas/core/window.py
elif not is_integer(self.window):
raise ValueError("window must be an integer")
答案 0 :(得分:3)
resample
和rolling
。pivot
/ unstack
在不处理重复A
/ B
的情况下,{I} groupby
和{{1} }} sum
一个级别unstack
所以我可以date
。目前,当我fill_value=0
一次超过一个级别时,我无法fill_value=0
。我用转置unstack
T
resample
答案 1 :(得分:1)
df = pd.DataFrame(X)
# group sum by day
df = df.groupby(['date', 'id', 'item'])['points'].sum().reset_index().sort_values(['date', 'id', 'item'])
# convert index to datetime index
df = df.set_index('date')
df.index = DatetimeIndex(df.index)
# rolloing sum by 3D
df['pointsum'] = df.groupby(['id', 'item']).transform(lambda x: x.rolling(window='3D').sum())
# reshape dataframe
df = df.reset_index().set_index(['date', 'id', 'item'])['pointsum'].unstack().reset_index().set_index('date').fillna(0)
df