![](/img/trans.png)
[英]Taking multiple slices of numpy 1d array from given indices, copying result into 2d array
[英]Efficiently slice windows from a 1D numpy array, around indices given by second 2D array
我想从同一个1D numpy数组中提取多个切片,其中切片索引是从随机分布中提取的。 基本上,我想实现以下目标:
import numpy as np
import numpy.random
# generate some 1D data
data = np.random.randn(500)
# window size (slices are 2*winsize long)
winsize = 60
# number of slices to take from the data
inds_size = (100, 200)
# get random integers that function as indices into the data
inds = np.random.randint(low=winsize, high=len(data)-winsize, size=inds_size)
# now I want to extract slices of data, running from inds[0,0]-60 to inds[0,0]+60
sliced_data = np.zeros( (winsize*2,) + inds_size )
for k in range(inds_size[0]):
for l in range(inds_size[1]):
sliced_data[:,k,l] = data[inds[k,l]-winsize:inds[k,l]+winsize]
# sliced_data.shape is now (120, 100, 200)
上面的嵌套循环工作正常,但速度很慢。 在我的真实代码中,我需要做数千次,因为数据阵列要比这些大得多。 有没有办法更有效地做到这一点?
请注意,在我的情况下, inds
总是2D,但在获得切片之后,我将总是在这两个维度中的一个上求和,因此只在一维上累积总和的方法就可以了。
我发现这个问题和答案看起来几乎一样。 然而,问题只是关于1D索引向量(与我的2D相反)。 此外,答案缺少一些上下文,因为我真的不明白建议的as_strided
是如何工作的。 由于我的问题似乎并不常见,我想我会再次提出问题,希望得到更具解释性的答案,而不仅仅是代码。
以这种方式使用as_strided
似乎比Divakar的方法(20 ms vs 35 ms)更快,尽管内存使用可能是一个问题。
data_wins = as_strided(data, shape=(data.size - 2*winsize + 1, 2*winsize), strides=(8, 8))
inds = np.random.randint(low=0, high=data.size - 2*winsize, size=inds_size)
sliced = data_wins[inds]
sliced = sliced.transpose((2, 0, 1)) # to use the same index order as before
Strides是每个维度中索引的步骤(以字节为单位)。 例如,对于形状(x, y, z)
的数组和大小为d
的数据类型(float64为8),步幅通常为(y*z*d, z*d, d)
,因此第二个索引跨越z行的整行。 将两个值都设置为8, data_wins[i, j]
和data_wins[j, i]
将引用相同的内存位置。
>>> import numpy as np
>>> from numpy.lib.stride_tricks import as_strided
>>> a = np.arange(10, dtype=np.int8)
>>> as_strided(a, shape=(3, 10 - 2), strides=(1, 1))
array([[0, 1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 4, 5, 6, 7, 8],
[2, 3, 4, 5, 6, 7, 8, 9]], dtype=int8)
这是使用broadcasting
的矢量化方法 -
# Get 3D offsetting array and add to inds for all indices
allinds = inds + np.arange(-60,60)[:,None,None]
# Index into data with all indices for desired output
sliced_dataout = data[allinds]
运行时测试 -
In [20]: # generate some 1D data
...: data = np.random.randn(500)
...:
...: # window size (slices are 2*winsize long)
...: winsize = 60
...:
...: # number of slices to take from the data
...: inds_size = (100, 200)
...:
...: # get random integers that function as indices into the data
...: inds=np.random.randint(low=winsize,high=len(data)-winsize, size=inds_size)
...:
In [21]: %%timeit
...: sliced_data = np.zeros( (winsize*2,) + inds_size )
...: for k in range(inds_size[0]):
...: for l in range(inds_size[1]):
...: sliced_data[:,k,l] = data[inds[k,l]-winsize:inds[k,l]+winsize]
...:
10 loops, best of 3: 66.9 ms per loop
In [22]: %%timeit
...: allinds = inds + np.arange(-60,60)[:,None,None]
...: sliced_dataout = data[allinds]
...:
10 loops, best of 3: 24.1 ms per loop
内存消耗:妥协解决方案
如果内存消耗是一个问题,这里是一个折衷的解决方案,一个循环 -
sliced_dataout = np.zeros( (winsize*2,) + inds_size )
for k in range(sliced_data.shape[0]):
sliced_dataout[k] = data[inds-winsize+k]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.