【问题标题】:How to index a high dimensional array with 2 index arrays如何用 2 个索引数组索引高维数组
【发布时间】:2021-11-25 12:48:41
【问题描述】:

我有一个 (2 x 1 x 2 x 2 x 2) 维数组:

array([[[[[ 7.,  9.],
          [10., 11.]],

         [[19., 18.],
          [20., 16.]]]],



       [[[[24.,  5.],
          [ 6., 10.]],

         [[18., 11.],
          [45., 12.]]]]])

最后两个维度分别是H(高度)和W(宽度)。现在我有两个单独的数组,索引沿 H 和 W:

idx2=np.array([1, 1, 0, 1]) # index along H
idx3=np.array([1, 0, 0, 0]) # index along W

因此,就最后两个维度而言,我想从[[ 7.,9.],[10.,11.]]中提取第(1,1)个元素,即11;以及来自[[19.,18.],[20.,16.]] 的第 (1,0) 个元素,即 20,依此类推。最终结果应该是一个(2 x 1 x 2)数组

array([[[11., 20.]],

       [[24., 45.]]])

感谢您的帮助!

【问题讨论】:

  • 为什么第三个数字是24.而不是10.
  • 因为它是来自[[24., 5.], [ 6., 10.]] 的第 (0,0) 个,即 24。同样,最后一个 45 是 [[18., 11.] 的第 (1,0) 个,[ 45., 12.]]
  • 我假设这个数组是用as_strided 生成的,就像你之前的问题一样。如果是这样,则数组是view。但是大多数高级索引形式都会创建一个副本,并“断开”到原始索引的链接。这同样适用于任何重塑。

标签: python numpy indexing


【解决方案1】:

查看numpy indexing

idx0=np.array([0,0,1,1])
idx1=np.array([0,1,0,1])
array[idx0,0,idx1,idx2,idx3]

另一种更 hacky 的方式:(我在我的代码中将数组命名为 a)

np.diag(a[:,:,:,idx2,idx3].reshape((4,-1))) 

在一般情况下,您必须将 4 替换为其他维度的乘积。

【讨论】:

  • 对于更复杂的索引,您必须使用numpy.org/doc/stable/reference/generated/numpy.ix_.html
  • 感谢您的回答,idx0 和 idx1 是什么?
  • ix_ 创建一个网格对吗?所以如果我使用 (4x1) idx2 和 (1x4) idx3 那么将检索到 4x4=16 个数字
  • 理想情况下,您可以只使用 array[:,:,:,idx2,idx3] 但是基本切片 + 高级索引不能那样工作。因此,您可以像@ivan 一样随身携带,也可以使用高级整数索引。为了高级索引,您需要前 3 个轴的整数索引。因为这是一个简单的案例,我可以简单地手写 idx0 和 idx1。但是对于更大的数组,可以使用 ix_ 创建 idx 0 和 idx 1。您真的应该阅读高级整数索引文档。
【解决方案2】:

使用np.ravel_multi_indexnp.take_along_axis 的组合解决此问题的可能方法。


您可以解开最后两个维度上的索引,并在此扁平空间维度 h x w 轴上使用 np.take_along_axis

>>> flat_idx = (idx2*x.shape[-1]+idx3).reshape(*x.shape[:-2], 1)
>>> flat_idx 
array([[[[3],
         [2]]],


       [[[0],
         [2]]]])

或者,你可以选择使用内置的np.ravel_multi_index,但是会稍微长一些:

>>> flat_idx = np.ravel_multi_index((idx2, idx3), x.shape[-2:]).reshape(*x.shape[:-2], 1)

然后展平x 的最后两个维度并收集索引:

>>> res = np.take_along_axis(x.reshape(*x.shape[:-2], -1), flat_idx, -1)
>>> res
array([[[[11.],
         [20.]]],


       [[[24.],
         [45.]]]])

此时需要重塑:

>>> res.reshape(*x.shape[0:-2])
array([[[11., 20.]],

       [[24., 45.]]])

如果你推断形状,idx2idx3 这归结为:

>>> flat_idx = (idx2*2+idx3).reshape(2, 1, 2, 1)
>>> res = np.take_along_axis(x.reshape(2, 1, 2, 4), flat_idx, -1)
>>> res.reshape((2, 1, 2))

上述方法可用于处理idx2idx3idx4、...等更一般的情况

【讨论】:

  • 这太棒了!谢谢伊万!
  • 感谢您的回答@Ivan。顺便说一句,您是否看到在这种情况下使用高级索引的方法?像 x[i,j,k,idx2,idx3]-->final (2x1x2) dim array 之类的东西?
  • 这里的高级索引是什么意思?
  • 喜欢numpy.org/doc/stable/reference/arrays.indexing.html?我不知道,只是想知道是否可以使用 x[some indices] 来获得最终结果。我已经尝试过,但无法正常工作。
  • 不确定,您似乎指的是不同的方法,这里我们不依赖索引,而是在扁平轴上使用未散列的索引。
【解决方案3】:

如果你有一个 2x1x2x2x2 维数组,array_name

import numpy as np
array_name = np.array([[[[[ 7.,  9.],
                          [10., 11.]],
                         [[19., 18.],
                          [20., 16.]]]],
                       [[[[24.,  5.],
                          [ 6., 10.]],
                         [[18., 11.],
                          [45., 12.]]]]])

array_name[0]array_name[1] 都是 1x2x2x2 维数组。

array_name[0].shape # (1, 2, 2, 2)

array_name[0][0] 是一个 2x2x2 维数组。

array_name[0][0].shape # (2, 2, 2)

array_name[0][0][0] 是一个 2x2 维数组。

array_name[0][0][0].shape # (2, 2)

array_name[0][0][0][0] 是一个二维数组。

array_name[0][0][0][0].shape # (2,)

对于问题中给出的数组:

array_name[0][0][0][1][1] # 11.
array_name[0][0][1][1][0] # 20.
array_name[1][0][0][0][0] # 24.
array_name[1][0][1][1][0] # 45.

此方法非常冗长,因此您可以使用高级索引。

idx_0 = [0,0,1,1]
idx_2 = [0,1,0,1]
idx_3 = [1,1,0,1]
idx_4 = [1,0,0,0]

每个idx_X 数组中的值取自上述详细代码中的数组索引,并用于创建一个包含 4 个元素的数组,如下所示。

array_name[idx_0, 0, idx_2, idx_3, idx_4]
# array([11., 20., 24., 45.])

【讨论】:

  • 感谢您的回答,但您的输出不是我想要的正确形状 (2x1x2)。实际上,您可以使用i,j,k=np.indices(array_name.shape[:-2]) 简单地获得这些领先指数idx_0、idx_1...,因此array_name[i.flatten(),j.flatten(),k,flatten(),idx2,idx3] 将给出[11,20,24,45]
猜你喜欢
  • 2018-01-22
  • 2017-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-20
  • 2019-07-28
  • 1970-01-01
相关资源
最近更新 更多