Python pandas - 按缺少日期的组有效地应用函数滚动 window
Python pandas - Efficiently apply function over rolling window by group with missing dates
注意:我已经知道这个问题的答案了,我发布它只是因为我找不到关于堆栈溢出的正确答案并且花了我惊人的时间弄明白。话虽这么说,请随时提出其他选择。
问题
我有一个包含三列的 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 偏移参数替换 window 的宽度(returns 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 所示。这实际上与上述选项非常相似。
使用rolling
的on
参数。 documentation actually mentions it, although there is no example to see the appropriate usage. Luckily, there is pandas github and this 问题,如果您仔细阅读评论,就会对如何正确使用带偏移 windows 的滚动函数提供一些见解。
因此,解决方案是:
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
。有关此问题的更多信息,请查看 Whosebug 问题 。
注意:我已经知道这个问题的答案了,我发布它只是因为我找不到关于堆栈溢出的正确答案并且花了我惊人的时间弄明白。话虽这么说,请随时提出其他选择。
问题
我有一个包含三列的 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 偏移参数替换 window 的宽度(returns 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 所示。这实际上与上述选项非常相似。
使用rolling
的on
参数。 documentation actually mentions it, although there is no example to see the appropriate usage. Luckily, there is pandas github and this 问题,如果您仔细阅读评论,就会对如何正确使用带偏移 windows 的滚动函数提供一些见解。
因此,解决方案是:
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
。有关此问题的更多信息,请查看 Whosebug 问题