【问题标题】:Slice numpy array by chunks按块切片numpy数组
【发布时间】:2018-07-23 19:54:58
【问题描述】:

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

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. aa 的第一个 N3 元素
  2. 跳转N2元素并添加N3的以下aa元素
  3. 重复 2. 直到 aa 用完

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

【问题讨论】:

  • 你为什么在这里使用list(…) 而不是直接使用aa[i * N2:(i * N2) + N3]?切片非常有效——你可以用 numpy 让它稍微simpler,但不会更快。但是将每个切片转换为列表非常慢,并且 numpy 不会做任何事情来加快速度。
  • 你的意思是跳转N2-N3个元素?
  • @abarnert 对不起,“直接使用aa[]”是什么意思?我使用 list 将此块添加到最终的 bb 数组中。如果我不这样做,我只会添加元素,而不是扩展列表。
  • @Gabriel 为什么你希望最终结果是一个列表?为什么不让它成为一个数组链,或者一个跨步数组?
  • 我不知道,这就是我发现的连接元素块的方式。

标签: python numpy slice


【解决方案1】:

只需重塑为 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:]

【讨论】:

  • 不错的 Divakar,比你又来了!
【解决方案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()

【讨论】:

    【解决方案3】:

    您可以使用 NumPy 的 array_splitsplit 更简单地执行相同的操作。

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

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

    但是,使用list(aa[i * N2:(i * N2) + N3]) 将每个切片转换为列表,然后扩展现有列表非常慢。它可能会占用您总时间的 99% 以上,因此优化其他 1% 是无关紧要的。 NumPy 无法加速将每个切片转换为列表。

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

    如果您确实需要一个列表,那本来就很慢,而且您无能为力。

    【讨论】:

    • 但我最终的bb 不是“列表列表”,而是单个平面列表。我不确定我是否理解这个答案,抱歉。
    • @Gabriel OK,已编辑。但核心点是一样的:列出是这里的缓慢部分。扩展列表很慢。而且你不需要做这些。
    • 是的,我明白这就是为什么我要求通过 numpy 切片来执行此操作。你提到的(链接 numpy 数组)也很慢。你是说它会比扩展列表更快吗?
    • @Gabriel 是的,制作切片数组列表并在其上调用chain 会比扩展列表快得多。根据您尝试对 bb 执行的操作,它可能有用,也可能没有。如果您的最终目标是使用 bb 作为可迭代对象,则链的迭代速度不会比列表快,但单个数组也不会,并且链将 build 快得多。如果您的目标是将bb 用作数组,那么链接不会对您有多大好处,您需要其他选项之一。由于不清楚您想用bb 做什么,因此很难详细说明如何操作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-11
    • 2011-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-28
    相关资源
    最近更新 更多