我有形状的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个参数。
- 数据
- 形状
- 进步
数据是上,我们将操作该阵列。
使用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