我有一个很大的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万条目的数组,它非常缓慢,有什么技巧可以使它更快?
我有一个很大的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万条目的数组,它非常缓慢,有什么技巧可以使它更快?
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)
我认为你目前的方法不能实现你所描述的功能。这里有一个更快的方法,使用列表推导将长数组分成多个子数组:
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
x
变量是什么? - lbragilenumpy.asarray
开始,如果你想要子数组,可以使用numpy.split
,或者使用numpy.reshape
代替你正在进行的任何串联操作。 - waffles