如何使用大小为 m 的滑动窗口将一个 numpy 数组分成 n 个子数组?

4

我有一个很大的NumPy数组,我想通过移动特定尺寸的窗口将其分割成多个子数组,在子数组大小为11的情况下,以下是我的代码:

import numpy as np

x = np.arange(10000)
T = np.array([])

for i in range(len(x)-11):
    s = x[i:i+11]
    T = np.concatenate((T, s), axis=0)

但是对于超过100万条目的数组,它非常缓慢,有什么技巧可以使它更快?


1
你的 x 变量是什么? - lbragile
我遇到了一个小错误,但我已经纠正了它,x是大数组。 - Fourat Thamri
我不知道你的总体目标是什么。但是你应该从numpy.asarray开始,如果你想要子数组,可以使用numpy.split,或者使用numpy.reshape代替你正在进行的任何串联操作。 - waffles
2个回答

3
实际上,这是使用as_strided的情况:
from numpy.lib.stride_tricks import as_strided

# set up
x = np.arange(1000000); windows = 11

# strides of x
stride = x.strides;

T = as_strided(x, shape=(len(x)-windows+1, windows), strides=(stride, stride))

输出:

array([[     0,      1,      2, ...,      8,      9,     10],
       [     1,      2,      3, ...,      9,     10,     11],
       [     2,      3,      4, ...,     10,     11,     12],
       ...,
       [999987, 999988, 999989, ..., 999995, 999996, 999997],
       [999988, 999989, 999990, ..., 999996, 999997, 999998],
       [999989, 999990, 999991, ..., 999997, 999998, 999999]])

性能:

5.88 µs ± 1.27 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

2

我认为你目前的方法不能实现你所描述的功能。这里有一个更快的方法,使用列表推导将长数组分成多个子数组:

代码修复:

import numpy as np 

x = np.arange(10000)
T = np.array([])

T = np.array([np.array(x[i:i+11]) for i in range(len(x)-11)])

速度比较:

sample_1 = '''
import numpy as np 

x = np.arange(10000)
T = np.array([])

for i in range(len(x)-11):
    s = x[i:i+11]
    T = np.concatenate((T, s),axis=0)

'''    

sample_2 = '''
import numpy as np 

x = np.arange(10000)
T = np.array([])

T = np.array([np.array(x[i:i+11]) for i in range(len(x)-11)])
'''

# Testing the times
import timeit
print(timeit.timeit(sample_1, number=1))
print(timeit.timeit(sample_2, number=1))

速度比较输出:

5.839815437000652   # Your method
0.11047088200211874 # List Comprehension

由于差异相当明显,我只检查了1个迭代,多个迭代也不会改变整体结果。

输出比较:

# Your method:
[  0.00000000e+00   1.00000000e+00   2.00000000e+00 ...,   9.99600000e+03
   9.99700000e+03   9.99800000e+03]

# Using List Comprehension:
[[   0    1    2 ...,    8    9   10]
 [   1    2    3 ...,    9   10   11]
 [   2    3    4 ...,   10   11   12]
 ..., 
 [9986 9987 9988 ..., 9994 9995 9996]
 [9987 9988 9989 ..., 9995 9996 9997]
 [9988 9989 9990 ..., 9996 9997 9998]]

您可以看到,我的方法实际上产生了子数组,而不像您提供的代码那样。

注意:

这些测试是在x上进行的,它只是从0到10000的有序数字列表。


另外请注意,range() 自动从 0 开始,因此无需指定。此外,由于连接而不是数组(数组的数组),您的代码生成了一个一维数组。 - lbragile
1
谢谢,它运行得很好,而且速度更快了。我正在调整输出以获得与您相同的结果。 - Fourat Thamri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接