Python pandas - 在缺少日期的情况下按组有效地将函数应用于滚动窗口

Posted

技术标签:

【中文标题】Python pandas - 在缺少日期的情况下按组有效地将函数应用于滚动窗口【英文标题】:Python pandas - Efficiently apply function over rolling window by group with missing dates 【发布时间】:2020-06-30 09:38:15 【问题描述】:

注意:我已经知道这个问题的答案,我发布它只是因为我找不到堆栈溢出的正确答案,而且我花了惊人的时间才弄清楚。话虽如此,请随时提出其他选择。

问题

我有一个包含三列的 pandas DataFrame,一列跟踪日期,一列跟踪相关观察结果(即我的分组列),第三个变量存储一些数值。对于我的数据框中的每个组,我想计算日期列的滚动总和。 警告:数据框中缺少某些日期,我想将它们视为值为 0 的观察值。我不想使用交叉连接来添加所有日期。

可重现的例子

让我们有一个这样的数据框:

df = pd.DataFrame('id_col' : np.array([1,1,1,1,1,1,2,2,2,2,2,3,3,3]),
                  'value_col' : np.random.randint(0,5,size=14),
                  'dates' : pd.to_datetime(np.array([
                  '2018-01-01',
                  '2018-02-01',
                  '2018-03-01',
                  '2018-05-01',
                  '2018-06-01',
                  '2018-09-01',
                  '2018-01-01',
                  '2018-02-01',
                  '2018-05-01',
                  '2018-06-01',
                  '2018-07-01',
                  '2018-01-01',
                  '2018-02-01',
                  '2018-03-01'])
                  )
                 )

数据看起来像这样:

    id_col  value_col   dates
0   1   0   2018-01-01
1   1   1   2018-02-01
2   1   4   2018-03-01
3   1   0   2018-05-01
4   1   3   2018-06-01
5   1   3   2018-09-01
6   2   4   2018-01-01
7   2   3   2018-02-01
8   2   2   2018-05-01
9   2   0   2018-06-01
10  2   2   2018-07-01
11  3   4   2018-01-01
12  3   2   2018-02-01
13  3   3   2018-03-01

我尝试过但不起作用的方法:

选项 1: 完全忽略缺失的日期

df.groupby(['id_col']).rolling(2)['value_col'].sum().reset_index()

选项 2: 基于 pandas rolling documentation,使用 pandas 偏移参数(返回 ValueError: window must be an integer)替换窗口宽度。如果将日期列用作数据框的索引,则此方法将起作用。不幸的是,我们不能在这里使用简单的索引,因为来自 id_col 的 2 个不同的 ID 可以包含相同的日期。 (我们可以创建 MultiIndex,但会得到相同的值错误)。

df.groupby(['id_col']).rolling('60d')['value_col'].sum().reset_index()

什么有效但不是很简单:

选项 1: 交叉联接以填写所有缺失的日期(如果您有大量数据可能会很困难)

选项 2: 从可迭代的笛卡尔积构建多索引,如 answer 所示。这实际上与上述选项非常相似。

【问题讨论】:

【参考方案1】:

使用rollingon 参数。 documentation 实际上提到了它,尽管没有示例可以看到适当的用法。幸运的是,有 pandas github 和 this 问题,如果您通过 cmets,可以了解如何正确使用具有偏移窗口的滚动功能。

因此,解决方案是:

df.groupby(['id_col']).rolling('60d', on = 'dates')['value_col'].sum().reset_index()

注意 60d 的使用作为 2 个月的代理而不是 2m 这是因为 2m 会给您以下错误:ValueError: <2 * MonthEnds> is a non-fixed frequency。有关此问题的更多信息,请查看 *** 问题here。

【讨论】:

以上是关于Python pandas - 在缺少日期的情况下按组有效地将函数应用于滚动窗口的主要内容,如果未能解决你的问题,请参考以下文章

在给定日期时间连续性的情况下,Pandas 输出日期、开始和结束时间以及事件状态

缺少日期的 Pandas Date MultiIndex - 滚动总和

如何在不使用 Pandas 的情况下创建等效于 numpy.nan 的日期时间对象?

Pandas - 根据之前的行为进行插值

有没有办法在不将 dtype 更改为对象的情况下将 NaT 附加到带有时区的 pandas 日期时间?

Python日历日期缺少空格