如何简单地计算python中时间序列的滚动/移动方差?

Bar*_*rry 12 python numpy time-series variance sliding-window

我有一个简单的时间序列,我正在努力估计移动窗口内的方差.更具体地说,我无法解决与实现滑动窗口功能的方式有关的一些问题.例如,使用NumPy和窗口大小= 20时:

def rolling_window(a, window):
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    strides = a.strides + (a.strides[-1],)
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides) 

rolling_window(data, 20)
np.var(rolling_window(data, 20), -1)
datavar=np.var(rolling_window(data, 20), -1)
Run Code Online (Sandbox Code Playgroud)

在这个想法中,也许我错了.有谁知道一个直截了当的方法吗?任何帮助/建议都是最受欢迎的.

ely*_*ase 13

你应该看看大熊猫.例如:

import pandas as pd
import numpy as np

# some sample data
ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000)).cumsum()

#plot the time series
ts.plot(style='k--')

# calculate a 60 day rolling mean and plot
pd.rolling_mean(ts, 60).plot(style='k')

# add the 20 day rolling variance:
pd.rolling_std(ts, 20).plot(style='b')
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

  • 我认为巴里正在寻找滚动的方差,而不是滚动的标准偏差.他可以对std求平方以获得方差或使用pd.rolling_var(ts,20).plot(style ='b'). (3认同)

sfj*_*jac 13

Pandas rolling_meanrolling_std函数已被弃用,并被更通用的"滚动"框架所取代.@ elyase的例子可以修改为:

import pandas as pd
import numpy as np
%matplotlib inline

# some sample data
ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000)).cumsum()

#plot the time series
ts.plot(style='k--')

# calculate a 60 day rolling mean and plot
ts.rolling(window=60).mean().plot(style='k')

# add the 20 day rolling standard deviation:
ts.rolling(window=20).std().plot(style='b')
Run Code Online (Sandbox Code Playgroud)

rolling函数支持许多不同的窗口类型,如此处所述.多个功能可以被称为上rolling对象,包括var和其他有趣的统计(skew,kurt,quantile等等).我一直坚持,std因为情节与平均值在同一图表上,这在单位方面更有意义.


Jos*_*ert 10

尽管是一个旧线程,但我会添加另一个从this修改的方法,它不依赖于熊猫,也不依赖于 python 循环。本质上,使用 numpy 的 stride 技巧,您可以首先创建一个带有 strides 的数组视图,这样沿着最后一个轴计算函数的统计量就相当于执行滚动统计量。我已经修改了原始代码,通过填充添加最后一个轴的开始,输出形状与输入形状相同。

import numpy as np

def rolling_window(a, window):
    pad = np.ones(len(a.shape), dtype=np.int32)
    pad[-1] = window-1
    pad = list(zip(pad, np.zeros(len(a.shape), dtype=np.int32)))
    a = np.pad(a, pad,mode='reflect')
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    strides = a.strides + (a.strides[-1],)
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

a = np.arange(30).reshape((5,6))

# rolling mean along last axis
np.mean(rolling_window(a, 3), axis=-1)

# rolling var along last axis
np.var(rolling_window(a, 3), axis=-1)

# rolling median along last axis
np.median(rolling_window(a, 3), axis=-1)

Run Code Online (Sandbox Code Playgroud)


Adr*_*aan 8

在我看来,使用 Pandas 来处理纯数值数据有点过分了;Bottleneck 效果很好,但自 2021 年 1 月以来一直没有更新,并且不再适用于 Python 3.9 及更高版本;所以我将发布一个基于Josh Albert 版本的版本,请记住文档注释lib.stride_tricks.as_strided,它可能使用起来不安全。

您可以使用 NumPy 的lib.stride_tricks.sliding_window_view(),它基本上是一个安全的包装器lib.stride_tricks.as_strided,来创建一个带有额外轴的数组,该轴的大小为窗口的大小(任意数量的维度),允许您使用 NumPy 的内置统计函数来操作穿过该轴:

import numpy as np

window = 3  # size of the window
A = np.arange(10)

Aw = np.lib.stride_tricks.sliding_window_view(A, window)
Avar = np.var(Aw, axis=-1)

Avar
>>> array([0.66666667, 0.66666667, 0.66666667, 0.66666667, 0.66666667,
       0.66666667, 0.66666667, 0.66666667])
Run Code Online (Sandbox Code Playgroud)

当然,这也适用于meanmaxminstd

注意:据我所知,无法包含数组的“边缘”,即A无法获得完整窗口长度的开头和结尾。因此,结果数组将被缩短到可以达到完整窗口长度的部分,请参阅返回的文档。


Rou*_*oux 5

我只是在寻找相同的解决方案,并发现瓶颈包应该非常可靠且快速地完成该任务。这是https://kwgoodman.github.io/bottleneck-doc/reference.html#bottleneck.move_var稍作调整的示例:

>>> import bottleneck as bn
>>> a = np.array([1.0, 2.0, 3.0, np.nan, 5.0])
>>> bn.move_var(a, window=2)
array([ nan,  0.25,  0.25,  nan,  nan])
>>> bn.move_var(a, window=2, min_count=1)
array([ 0. ,  0.25,  0.25,  0. ,  0. ])
Run Code Online (Sandbox Code Playgroud)

请注意,所得方差对应于窗口的最后一个索引。

该软件包可从 Ubuntu repos、pip 等获取。它可以在 numpy-array 等的任意轴上运行。除此之外,据称在许多情况下它比普通 numpy 实现更快。