按块切片numpy数组

时间:2018-07-23 19:54:59

标签: python numpy slice

我需要根据给定切片条件的三个值(aa)对数组(N1, N2, N3)进行切片,如下所示:

import numpy as np

N1, N2, N3 = 200, 500000, 30
aa = np.random.uniform(0., 1., N1*N2)

bb = []
for i in range(N1):
    bb += list(aa[i * N2:(i * N2) + N3])

此代码遵循以下规则生成新数组bb

  1. N3的前aa个元素
  2. 跳转N2元素并添加N3的以下aa元素
  3. 重复2。直到aa用尽

我可以通过numpy索引更快地执行此过程吗?

3 个答案:

答案 0 :(得分:3)

仅需重塑为2D并切片前N3列-

bb = aa.reshape(N1,N2)[:,:N3].ravel()

N3超过N2

如果N3超过N2,则这些aa[i * N2:(i * N2) + N3]在迭代中会重叠。为了解决这种情况,我们可以创建滑动窗口,然后切片行,直到我们有足够的长度,然后为剩余的窗口创建一个循环-

from skimage.util.shape import view_as_windows

starts = np.arange(len(aa), step=N2)
lens = len(aa) - np.arange(len(aa), step=N2)
rem_lens = lens[lens < N3]
m0 = lens < N3

l1 = N3*(~m0).sum()
l2 = rem_lens.sum() 
out = np.empty(l1+l2, dtype=aa.dtype)
out[:l1] = view_as_windows(aa,(N3))[::N2].ravel()
rem_starts = starts[m0]
ss = l1+np.r_[0,rem_lens.cumsum()]
for s,i,j in zip(rem_starts, ss[:-1], ss[1:]):
    out[i:j] = aa[s:]

答案 1 :(得分:2)

您可以通过重塑数组来更优雅地完成此操作。首先将初始数组设为2D:

N1, N2, N3 = 200, 500000, 30
aa = np.random.uniform(0., 1., (N1, N2))

现在,只需在第二维上删除大小为N3的块即可:

bb = aa[:, :N3]

如果您需要bb使其平坦,请使其平坦

bb = aa[:, :N3].ravel()

答案 2 :(得分:0)

您可以使用NumPy的array_splitsplit来更简单地完成相同的事情。

但是,效率可能不会显着提高。

使用aa[i * N2:(i * N2) + N3]存储一堆数组切片是切片数量的线性时间。在NumPy内执行该循环(因此,假设您使用的是CPython,则在C循环而不是Python循环中执行)会更快一些。但是,除非您有大量的切片,否则可能没关系。

但是,使用list(aa[i * N2:(i * N2) + N3])将每个分片转换为列表,然后扩展现有列表非常慢。这可能要花费您总时间的99%以上,因此优化其他1%的问题是无关紧要的。 NumPy无法做任何加速将每个片段转换为列表的事情。

因此,如果您实际上不需要列表,只需停止调用list。您可以只使用数组列表,并根据需要chain一起使用它们,也可以在数组列表中构建a custom-strided array,也可以ravel将原始数组变成形状你想要的。

如果您要做需要一个列表,这从本质上来说很慢,而且您无能为力。