【发布时间】:2017-10-29 06:42:23
【问题描述】:
我想将滚动函数应用于按两列分组的数据框,其中包含重复的日期条目。具体来说,“频率”和“窗口”都作为日期时间值,而不仅仅是整数。
原则上,我尝试结合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
例如在包含右端的结束日期 2017-02-13 上,我们对 2017-02-11 至 2017-02-13 的 3 天期间进行抽样。在此期间,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 迄今为止的好建议
备注
熊猫版本 = 0.20.1
我有点困惑为什么关于 rolling() 的文档在这里:https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.rolling.html
建议“窗口”参数可以是 int 或偏移量,但在尝试 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")
【问题讨论】:
标签: pandas group-by time-series