M-通过-N shpae numpy.ndarray的滑动窗口(sliding window of

2019-08-18 08:18发布

我有形状的numpy的阵列(6,2)

[[00,01],
 [10,11],
 [20,21],
 [30,31],
 [40,41],
 [50,51]]

我需要与步长1和窗口大小3滑动窗口喜欢这样的:

[[00,01,10,11,20,21],
 [10,11,20,21,30,31],
 [20,21,30,31,40,41],
 [30,31,40,41,50,51]]

我正在寻找一个numpy的解决方案。 如果您的解决方案可以参数化的原数组的形状以及窗口大小和步长,那简直太棒了。

我发现这个答案的相关使用了高效的移动平均滤波器的进步 ,但我看不出如何有指定的步长,以及如何从3D折叠窗口连续二维数组。 另外这个滚动或在Python滑动窗口迭代但这是在Python和我不知道这是多么有效。 此外,它支持元素,但并没有最终将它们连接在一起,如果每个元素都有多种功能。

Answer 1:

In [1]: import numpy as np

In [2]: a = np.array([[00,01], [10,11], [20,21], [30,31], [40,41], [50,51]])

In [3]: w = np.hstack((a[:-2],a[1:-1],a[2:]))

In [4]: w
Out[4]: 
array([[ 0,  1, 10, 11, 20, 21],
       [10, 11, 20, 21, 30, 31],
       [20, 21, 30, 31, 40, 41],
       [30, 31, 40, 41, 50, 51]])

你可以在写这篇文章的功能,像这样:

def window_stack(a, stepsize=1, width=3):
    n = a.shape[0]
    return np.hstack( a[i:1+n+i-width:stepsize] for i in range(0,width) )

这并不真正取决于原始阵列的形状,只要a.ndim = 2 。 请注意,我从来没有使用任何长度的交互式版本。 形状的第二维是无关紧要; 每行可以,只要你想要的。 感谢@海梅的建议,你可以不用在所有检查的形状:

def window_stack(a, stepsize=1, width=3):
    return np.hstack( a[i:1+i-width or None:stepsize] for i in range(0,width) )


Answer 2:

您可以使用索引看中在numpy的做一个矢量滑动窗口。

>>> import numpy as np

>>> a = np.array([[00,01], [10,11], [20,21], [30,31], [40,41], [50,51]])

>>> a
array([[ 0,  1],
       [10, 11],
       [20, 21],                      #define our 2d numpy array
       [30, 31],
       [40, 41],
       [50, 51]])

>>> a = a.flatten()

>>> a
array([ 0,  1, 10, 11, 20, 21, 30, 31, 40, 41, 50, 51])    #flattened numpy array

>>> indexer = np.arange(6)[None, :] + 2*np.arange(4)[:, None]

>>> indexer
array([[ 0,  1,  2,  3,  4,  5],
       [ 2,  3,  4,  5,  6,  7],            #sliding window indices
       [ 4,  5,  6,  7,  8,  9],
       [ 6,  7,  8,  9, 10, 11]])

>>> a[indexer]
array([[ 0,  1, 10, 11, 20, 21],
       [10, 11, 20, 21, 30, 31],            #values of a over sliding window
       [20, 21, 30, 31, 40, 41],
       [30, 31, 40, 41, 50, 51]])

>>> np.sum(a[indexer], axis=1)
array([ 63, 123, 183, 243])         #sum of values in 'a' under the sliding window.

解释一下这个代码在做什么。

所述np.arange(6)[None, :]至6创建一个行向量0, np.arange(4)[:, None]通过4.创建一个列向量0这将导致一个4x6的矩阵,其中每行(它们)的6代表一个窗口,和行(其中四个数)表示窗口的数量。 的2的多使得滑动窗口滑动2个单位在时间所必需的滑过每个元组。 使用numpy的数组切片你可以通过滑动窗口到展平numpy的数组并聚集在他们身上同样数目的钱。



Answer 3:

解决的办法是

np.lib.stride_tricks.as_strided(a, shape=(4,6), strides=(8,4))

使用进展非常直观,当你在指针/地址方面开始思考。

所述as_strided()方法具有3个参数。

  1. 数据
  2. 形状
  3. 进步

数据是上,我们将操作该阵列。

使用as_strided()用于实现滑动窗口的功能,就必须预先计算输出的形状。 在的问题,(4,6)是输出的形状。 如果尺寸是不正确的,我们最终读书无用值。 这是因为我们通过由一对夫妇字节(取决于数据类型)的移动指针访问数据。

确定步伐的正确值是必不可少的获得预期的效果。 计算的进步之前,找出由每个使用元件所占用的存储器arr.strides[-1] 。 在此实例中,通过一个元件所占用的存储器是4个字节。 numpy的数组行的主要方式创建。 下一行的第一个元素是紧邻当前行的最后一个元素的权利。

例如:0,1 | 10,11 | ...

图10是毗邻1。

想象2D阵列重新成形至1D(作为数据被存储在一个行优先格式这是可接受的)。 在输出的每一行的第一个元素是一维阵列中的奇数索引的元素。 0,10,20,30,..

因此,在存储器我们需要采取移动从0至10,10至20,等步骤的数目是2 *元件的MEM大小 。 每一行具有2 * 4字节= 8步幅对于在输出的给定行,所有的元素都在我们的假想1D阵列彼此相邻。 要获得连续的下一个元素,只取了一大步等于元素的大小。 柱步幅的值是4个字节。

因此, strides=(8,4)

一种替代解释:输出具有(4,6)的形状。 列步幅4 。 所以,第一行的元素在索引开始0 ,并且具有每个间隔开的4个字节6层的元件。 在第一行被收集之后,在第二行开始从当前行的起始的8个字节的路程。 第三行开始从第二行的起点8个字节远等。

形状决定了我们需要的行数和列数。 进展定义存储步骤来启动一排,并收集一列元件



Answer 4:

短名单的理解是可能的more_itertools.windowed 1:

特定

import numpy as np
import more_itertools as mit


a = [["00","01"],
     ["10","11"],
     ["20","21"],
     ["30","31"],
     ["40","41"],
     ["50","51"]]

b = np.array(a)

np.array([list(mit.flatten(w)) for w in mit.windowed(a, n=3)])

要么

np.array([[i for item in w for i in item] for w in mit.windowed(a, n=3)])

要么

np.array(list(mit.windowed(b.ravel(), n=6)))

产量

array([['00', '01', '10', '11', '20', '21'],
       ['10', '11', '20', '21', '30', '31'],
       ['20', '21', '30', '31', '40', '41'],
       ['30', '31', '40', '41', '50', '51']], 
      dtype='<U2')

滑动尺寸的窗口n=3创建和平坦化。 注意默认步长more_itertools.windowed(..., step=1)


性能

作为一个数组,接受的答案是最快的。

%timeit np.hstack((a[:-2], a[1:-1], a[2:]))
# 37.5 µs ± 1.88 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit np.hstack((b[:-2], b[1:-1], b[2:]))
# 12.9 µs ± 166 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit np.array([list(mit.flatten(w)) for w in mit.windowed(a, n=3)])
# 23.2 µs ± 1.73 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit np.array([[i for item in w for i in item] for w in mit.windowed(a, n=3)])
# 21.2 µs ± 999 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit np.array(list(mit.windowed(b.ravel(), n=6)))
# 43.4 µs ± 374 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

第三方库,实现itertool食谱和许多有用的工具。



文章来源: sliding window of M-by-N shpae numpy.ndarray