我想从同一个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)