【问题标题】:How to use Pandas rolling_* functions on a forward-looking basis如何前瞻性地使用 Pandas rolling_* 函数
【发布时间】:2014-05-14 06:11:37
【问题描述】:

假设我有一个时间序列:

In[138] rng = pd.date_range('1/10/2011', periods=10, freq='D')
In[139] ts = pd.Series(randn(len(rng)), index=rng)
In[140]
Out[140]:
2011-01-10    0
2011-01-11    1
2011-01-12    2
2011-01-13    3
2011-01-14    4
2011-01-15    5
2011-01-16    6
2011-01-17    7
2011-01-18    8
2011-01-19    9
Freq: D, dtype: int64

如果我使用 rolling_* 函数之一,例如 rolling_sum,我可以获得我想要的回溯滚动计算行为:

In [157]: pd.rolling_sum(ts, window=3, min_periods=0)
Out[157]: 
2011-01-10     0
2011-01-11     1
2011-01-12     3
2011-01-13     6
2011-01-14     9
2011-01-15    12
2011-01-16    15
2011-01-17    18
2011-01-18    21
2011-01-19    24
Freq: D, dtype: float64

但是如果我想做一个前瞻性的求和呢?我试过这样的事情:

In [161]: pd.rolling_sum(ts.shift(-2, freq='D'), window=3, min_periods=0)
Out[161]: 
2011-01-08     0
2011-01-09     1
2011-01-10     3
2011-01-11     6
2011-01-12     9
2011-01-13    12
2011-01-14    15
2011-01-15    18
2011-01-16    21
2011-01-17    24
Freq: D, dtype: float64

但这并不是我想要的行为。我正在寻找的输出是:

2011-01-10    3
2011-01-11    6
2011-01-12    9
2011-01-13    12
2011-01-14    15
2011-01-15    18
2011-01-16    21
2011-01-17    24
2011-01-18    17
2011-01-19    9

ie - 我想要“当前”日期加上接下来两天的总和。我目前的解决方案还不够,因为我关心边缘发生的事情。我知道我可以通过设置两个分别移动 1 天和 2 天的额外列然后将这三列相加来手动解决这个问题,但必须有一个更优雅的解决方案。

【问题讨论】:

  • 我从大约一年前找到了this thread,所以看起来还没有“官方”支持。但是那里发布的临时解决方案也没有做我想要的边缘(我的例子中的第 18/19 仍然是空白的)
  • Pandas 1.1 添加了对带有FixedForwardWindowIndexer 的前瞻性窗口操作的“支持”,但是当我尝试将其应用于这些数据时,我的解释器出现了段错误......也许这还不支持前向日期时间窗口但是最终会的。

标签: python pandas


【解决方案1】:

为什么不只在颠倒的系列上做(并颠倒答案):

In [11]: pd.rolling_sum(ts[::-1], window=3, min_periods=0)[::-1]
Out[11]:
2011-01-10     3
2011-01-11     6
2011-01-12     9
2011-01-13    12
2011-01-14    15
2011-01-15    18
2011-01-16    21
2011-01-17    24
2011-01-18    17
2011-01-19     9
Freq: D, dtype: float64

【讨论】:

  • 聪明的回答,谢谢。尽管这仅在您拥有一个范围内的所有日期时才有效。在您的情况下,您没有指定频率。例如,当您指定 freq='D' 时,此解决方案不再有效。因此,如果我缺少数据或采样频率可变,这将不起作用。看起来这将是一个非常有价值的功能,可以正确实施。有谁知道它是否正在筹备中?
  • @user2543645 我创建了一个关于此here 的问题。我没有意识到这在某些情况下不起作用,很有趣。你可以先重新采样(以获得一致的频率)然后再反向滚动?
  • 我认为这应该可行,但前提是您以要聚合的频率重新采样。如果您有稀疏数据,这可能会大大增加您的集合大小。例如,如果您在不同年份收集了几天的每小时观测值,则必须添加数千个空值。如果有一个更加原生的支持,它的行为方式与 rolling_* 的行为方式相同,只是在另一个方向上,那就太好了。
【解决方案2】:

我为此苦苦挣扎,然后找到了一种使用 shift 的简单方法。

如果您想要接下来 10 个期间的滚动总和,请尝试:

df['NewCol'] = df['OtherCol'].shift(-10).rolling(10, min_periods = 0).sum()

我们使用 shift 以使“OtherCol”比通常显示的位置提前 10 行,然后我们对前 10 行进行滚动求和。因为我们移位了,前 10 行实际上是未移位列的未来 10 行。 :)

【讨论】:

  • 似乎是一个不错的方法,但我相信您会丢失最初的 10 行,不是吗?
【解决方案3】:

Pandas 最近添加了一项新功能,可让您实现前瞻性滚动。您必须升级到 pandas 1.1.0 才能获得new feature

indexer = pd.api.indexers.FixedForwardWindowIndexer(window_size=3)
ts.rolling(window=indexer, min_periods=1).sum()

【讨论】:

  • 这仅适用于您有完整的不间断日期系列。您不能使用 rolling() 可以使用的 '#D' 窗口
【解决方案4】:

也许你可以试试bottleneck 模块。当ts 很大时,bottleneckpandas 快​​得多

import bottleneck as bn
result = bn.move_sum(ts[::-1], window=3, min_count=1)[::-1]

bottleneck还有其他滚动功能,如move_maxmove_argminmove_rank

【讨论】:

    猜你喜欢
    • 2014-06-11
    • 1970-01-01
    • 2017-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-16
    • 2018-01-20
    • 2018-01-06
    相关资源
    最近更新 更多