从另一个二维数组中提取具有指定索引的元素

3

我有一个2d的numpy数组:data.shape==(n,8),还有另一个ind.shape=(n,4)的数组。ind数组和data长度相等,包含像[4,3,0,6]这样的索引。我该如何创建另一个形状为(n,4)的数组,其中包含由ind指定的data元素?我的实际数组很长(shape[0]),所以循环速度很慢。必须有比循环更好的方法吧?

import numpy as np
# Example data
data = np.array([[ 0.44180102, -0.05941365,  2.1482739 , -0.56875081, -1.45400572,
        -1.44391254, -0.33710766, -0.44214518],
       [ 0.79506417, -2.46156966, -0.09929341, -1.07347179,  1.03986533,
        -0.45745476,  0.58853107, -1.08565425],
       [ 1.40348682, -1.43396403,  0.8267174 , -1.54812358, -1.05854445,
         0.15789466, -0.0666025 ,  0.29058816]])
ind = np.array([[3, 4, 1, 5],
                [4, 7, 0, 1],
                [5, 1, 3, 6]])

# This is the part I want to vectorize:
out = np.zeros(ind.shape)
for i in range(ind.shape[0]):
    out[i,:] = data[i,ind[i,:]]

# This should be good
assert np.all(out == np.array([[-0.56875081, -1.45400572, -0.05941365, -1.44391254],
                        [ 1.03986533, -1.08565425,  0.79506417, -2.46156966],
                        [ 0.15789466, -1.43396403, -1.54812358, -0.0666025 ]]))
2个回答

5

如果我们索引到了压缩的data数组中,这就可以很容易地实现:

out = data.ravel()[ind.ravel() + np.repeat(range(0, 8*ind.shape[0], 8), ind.shape[1])].reshape(ind.shape)

解释

如果将其分为三个步骤可能更容易理解:

indices = ind.ravel() + np.repeat(range(0, 8*ind.shape[0], 8), ind.shape[1])
out = data.ravel()[indices]
out = out.reshape(ind.shape)

ind 包含了我们想要的 data 元素的信息。不幸的是,它是用二维索引表示的。上面的第一行将其转换为 1-D 展平的 data 的索引。上面的第二行选取展平数组 data 中的这些元素。第三行将 2-D 的形状恢复到 out

ind 表示的二维索引被转换为 indices 索引


3
你想要的是这样的效果:

你需要类似以下的内容:

import numpy as np
data = np.array([[ 0.4, -0.1,  2.1, -0.6, -1.5, -1.4, -0.3, -0.4],
                 [ 0.8, -2.5, -0.1, -1.1,  1. , -0.5,  0.6, -1.1],
                 [ 1.4, -1.4,  0.8, -1.5, -1.1,  0.2, -0.1,  0.3]])
expected = np.array([[-0.6, -1.5, -0.1, -1.4],
                     [ 1. , -1.1,  0.8, -2.5],
                     [ 0.2, -1.4, -1.5, -0.1]])

indI = np.array([[0, 0, 0, 0],
                 [1, 1, 1, 1],
                 [2, 2, 2, 2]])
indJ = np.array([[3, 4, 1, 5],
                 [4, 7, 0, 1],
                 [5, 1, 3, 6]])
out = data[indI, indJ]
assert np.all(out == expected)

请注意,indIindJ具有相同的形状,并且:
out[i, j] == data[indI[i, j], indJ[i, j]]

对于所有的 ij

您可能已经注意到,indI 非常重复。由于 numpy 的 广播 魔法,您可以简单地将 indI 改为:

indI = np.array([[0],
                 [1],
                 [2]])

您可以用几种不同的方法构建这种indI数组,以下是我最喜欢的方法:
a, b = indJ.shape
indI, _ = np.ogrid[:a, :0]
out = data[indI, indJ]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接