NumPy对多维数组的精确索引:文档未涵盖(明确)的情况

时间:2014-06-17 14:51:07

标签: python arrays numpy indexing

NumPy文档here告诉我们以下内容不起作用:

>>> test_array[np.array([0,2,4]), np.array([0,1])]
<type 'exceptions.ValueError'>: shape mismatch: objects cannot be
broadcast to a single shape

但是,如果我们必须做某种事情,应该怎么做?目前,我使用Python列表理解:

test_array = np.array([ [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ], 
                      [ [10, 11, 12], [13, 14, 15], [16, 17, 18] ], 
                      [ [19, 20, 21], [22, 23, 24], [25, 26, 27] ], 
                      [ [28, 29, 30], [31, 32, 33], [34, 35, 36] ] ])
xs = [0, 2, 3]
ys = [0, 2]
>>> np.array([test_array[x, y] for x, y in list(itertools.product(xs, ys))])
array([[ 1,  2,  3],
       [ 7,  8,  9],
       [19, 20, 21],
       [25, 26, 27],
       [28, 29, 30],
       [34, 35, 36]])

我怀疑这是否有效!

4 个答案:

答案 0 :(得分:1)

你发布的代码不起作用,所以有点猜测,但我认为这就是你所追求的:

>>> y = np.arange(30).reshape(5, 6)
>>> xs = [0, 2, 4]
>>> ys = [0, 1]
>>> np.array([y[xy] for xy in itertools.product(xs, ys)])
array([ 0,  1, 12, 13, 24, 25])
>>> y[np.array(xs)[:, None], ys]
array([[ 0,  1],
       [12, 13],
       [24, 25]])
>>> y[np.array(xs)[:, None], ys].ravel()
array([ 0,  1, 12, 13, 24, 25])

编辑您的更新代码可以同样工作,但不是很漂亮:

>>> test_array[np.array(xs)[:, None], ys].reshape(-1, test_array.shape[-1])
array([[ 1,  2,  3],
       [ 7,  8,  9],
       [19, 20, 21],
       [25, 26, 27],
       [28, 29, 30],
       [34, 35, 36]])

答案 1 :(得分:1)

如果在numpy中使用np.ix_进行索引,则为此类。

import numpy as np
test_array = np.array([ [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ], 
                      [ [10, 11, 12], [13, 14, 15], [16, 17, 18] ], 
                      [ [19, 20, 21], [22, 23, 24], [25, 26, 27] ], 
                      [ [28, 29, 30], [31, 32, 33], [34, 35, 36] ] ])
xs = [0, 2, 3]
ys = [0, 2]
res = test_array[np.ix_(xs, ys)]
print res.shape
# (3, 2, 3)

结果是(3,2,3),因为xy,ys的长度和数组的最后一个维度分别为3,2,3。如果您希望结果为(6,3),只需在索引后重新整形:

i, j, k = res.shape
res = res.reshape((i * j, k))
print res.shape
# (6, 3)
print res
# array([[ 1,  2,  3],
#        [ 7,  8,  9],
#        [19, 20, 21],
#        [25, 26, 27],
#        [28, 29, 30],
#        [34, 35, 36]])

对于任何有兴趣的人来说,np.ix_只是一个便条,只是@Jamie答案中使用的魔术广播的便利功能。如果您想知道它的工作原理,请查看他的答案,并在numpy's broadcasting上阅读。

答案 2 :(得分:0)

这种语法是可行的。

tmp = y[np.array([0, 2, 4]), np.array([0, 1, 1])]

给出与以下相同的结果:

tmp = np.array([y[0, 0], y[2, 1], y[4, 1]])

以下是一个例子:

>>> y = np.arange(15).reshape(5, 3)
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]
 [12 13 14]]
>>> y[np.array([0, 2, 4]), np.array([0, 1, 1])]
[ 0  7 13]
>>> np.array([y[0, 0], y[2, 1], y[4, 1]])
[ 0  7 13]

因此,您提出的语法是错误的,因为两个索引列表不具有相同的形状。

答案 3 :(得分:0)

这不是一般的解决方案,但它符合您的示例的期望:

import numpy as np
import itertools as it
test_array = np.array([ [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ], [ [10, 11, 12], [13, 14, 15], [16, 17, 18] ], [ [19, 20, 21], [22, 23, 24], [25, 26, 27] ], [ [28, 29, 30], [31, 32, 33], [34, 35, 36] ] ])
xs = [0, 2, 3]
ys = [0, 2]
expected =  np.array([test_array[x, y] for x, y in list(it.product(xs, ys))])

new = test_array[xs,...][:,ys, ...]
new = new.reshape(np.multiply(*new.shape[:-1]), new.shape[-1])
assert np.all(new == expected)