【问题标题】:Rolling window for 1D arrays in Numpy?Numpy中一维数组的滚动窗口?
【发布时间】:2011-10-12 06:37:21
【问题描述】:

有没有办法在 Numpy 中有效地实现一维数组的滚动窗口?

例如,我有这个纯 Python 代码 sn-p 来计算一维列表的滚动标准差,其中 observations 是一维值列表,n 是标准差的窗口长度:

stdev = []
for i, data in enumerate(observations[n-1:]):
    strip = observations[i:i+n]
    mean = sum(strip) / n
    stdev.append(sqrt(250*sum([(s-mean)**2 for s in strip])/(n-1)))

有没有办法在 Numpy 中完全做到这一点,即没有任何 Python 循环? numpy.std 的标准差微不足道,但滚动窗口部分完全让我难过。

我发现this 博客文章关于 Numpy 中的滚动窗口,但它似乎不适用于一维数组。

【问题讨论】:

标签: python python-3.x numpy window


【解决方案1】:

只需使用博客代码,但将您的函数应用于结果。

numpy.std(rolling_window(observations, n), 1)

你在哪里(来自博客):

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)

【讨论】:

  • 这可以扩展到n-d数组的轴吗?
  • 另外如何使用它来创建跨步重叠?
  • @Gulzar,如果您还没有,请在下面查看我的答案。 so12311 的函数实际上适用于 n-d 数组,其移动窗口沿最后一个轴移动。我的函数适用于沿第一个轴移动窗口的 n-d 数组。如果您需要沿中间轴滚动,则需要拆分步幅和形状,并在适当的位置添加额外的元素。我不知道你的意思是重叠,但你可以用不同的步幅和形状来实现它。考虑提出一个新问题,详细说明您的具体需求。
  • @LelandHepworth 谢谢。我所说的重叠是指数组 [1, 2, 3, 4, 5] 的例子,我想要一些方法来获得 [1, 2, 3][2, 3, 4][3, 4, 5] 例如。
  • @Gulzar,使用任一版本的函数,以下内容应该可以满足您的需求:rolling_window(np.array([1, 2, 3, 4, 5]), 3)
【解决方案2】:

Numpy 1.20开始,可以直接用sliding_window_view得到滚动窗口:

from numpy.lib.stride_tricks import sliding_window_view

sliding_window_view(np.array([1, 2, 3, 4, 5, 6]), window_shape = 3)
# array([[1, 2, 3],
#        [2, 3, 4],
#        [3, 4, 5],
#        [4, 5, 6]])

【讨论】:

  • 这应该是公认的答案。
【解决方案3】:

我尝试在形状为[samples, features] 的二维数组上使用so12311answer listed above 以获得形状为[samples, timesteps, features] 的输出数组,用于卷积或lstm 神经网络,但它不是工作得很好。在深入了解了 strides 的工作原理后,我意识到它正在沿最后一个轴移动窗口,因此我进行了一些调整,以便将窗口改为沿第一个轴移动:

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

注意:如果您只使用一维输入数组,则输出没有区别。在我的搜索中,这是第一个接近我想要做的结果,所以我添加它以帮助任何其他搜索类似答案的人。

【讨论】:

    【解决方案4】:

    只有一行代码...

    import pandas as pd
    
    pd.Series(observations).rolling(n).std()
    

    【讨论】:

      【解决方案5】:
      def moving_avg(x,n):
          mv =  np.convolve(x,np.ones(n)/n,mode='valid')
          return np.concatenate(([np.NaN for k in range(n-1)],mv))
      

      【讨论】:

        【解决方案6】:

        根据后面的答案,在这里我添加代码用于滚动一维 numpy 数组,选择 window sizewindow steps frequency

        a = np.arange(50)
        
        def rolling_window(array, window_size,freq):
            shape = (array.shape[0] - window_size + 1, window_size)
            strides = (array.strides[0],) + array.strides
            rolled = np.lib.stride_tricks.as_strided(array, shape=shape, strides=strides)
            return rolled[np.arange(0,shape[0],freq)]
        
        rolling_window(a,10,5)
        

        输出:

        array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
               [ 5,  6,  7,  8,  9, 10, 11, 12, 13, 14],
               [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
               [15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
               [20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
               [25, 26, 27, 28, 29, 30, 31, 32, 33, 34],
               [30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
               [35, 36, 37, 38, 39, 40, 41, 42, 43, 44],
               [40, 41, 42, 43, 44, 45, 46, 47, 48, 49]])
        
        

        【讨论】:

          猜你喜欢
          • 2017-01-05
          • 2011-12-31
          • 2017-04-02
          • 2019-01-06
          • 2015-12-16
          • 1970-01-01
          • 2018-05-08
          • 2017-10-13
          • 1970-01-01
          相关资源
          最近更新 更多