Python numpy:花式索引“;“意外行为”奇特的索引似乎给出的结果是;转置;直觉上的预期

Python numpy:花式索引“;“意外行为”奇特的索引似乎给出的结果是;转置;直觉上的预期,python,numpy,Python,Numpy,我对花式索引的行为有点困惑,请参见: >>> t = np.arange(2*2*3).reshape((2, 2, 3)) >>> t array([[[ 0, 1, 2], [ 3, 4, 5]], [[ 6, 7, 8], [ 9, 10, 11]]]) >>> t[1, :, [1, 2]] array([[ 7, 10], [ 8, 11]]) 我以为在使用

我对花式索引的行为有点困惑,请参见:

>>> t = np.arange(2*2*3).reshape((2, 2, 3))
>>> t
array([[[ 0,  1,  2],
        [ 3,  4,  5]],

       [[ 6,  7,  8],
        [ 9, 10, 11]]])
>>> t[1, :, [1, 2]]
array([[ 7, 10],
       [ 8, 11]])
我以为在使用
t[1,:,[1,2]]
索引后,我会得到数组:

array([[ 7,  8],
       [10, 11]])
但是我得到的是转换姿势,如上图所示

也可以考虑如下:

>>> t[:, :, [1, 2]][1]
array([[ 7,  8],
       [10, 11]])
这并没有遵循我们刚才提到的不直观的行为模式……它的行为“如预期的那样”。为什么?


为什么会出现这种行为,如何才能达到预期的行为?

如果在任何先前的轴中存在非切片,行为似乎会发生变化:

>>> import numpy as np
>>> t = np.arange(2*2*3).reshape((2, 2, 3))

>>> t[1:2, :, [1, 2]]   # 1 -> 1:2  (slicing)
array([[[ 7,  8],
        [10, 11]]])

>>> t[1][:, [1, 2]]
array([[ 7,  8],
       [10, 11]])

在简单情况下(即一个索引数组 和N-1个切片对象)它完全符合您的期望(将 重复应用基本切片)

在这种情况下,索引数组是[1,2],切片对象是
1
(或者更准确地说,
slice(1,2)
,和
slice(None)
):

因此,结果是切片的串联

In [43]: t[1,:,1]
Out[43]: array([ 7, 10])

In [44]: t[1,:,2]
Out[44]: array([ 8, 11])
还要注意,
t[1,:,[1,2]]
的形状将是(2,2),因为标量为1 删除0轴,且
跨越所有轴1(长度为2)和[1,2] 长度为2。因此,当您运行结果的最后一个(即第二个)轴时,您将得到数组
数组([7,10])
数组([8,11])

获得所需结果的最简单方法是使用基本切片

In [45]: t[1, :, 1:3]
Out[45]: 
array([[ 7,  8],
       [10, 11]])
另一种使用“奇特”整数索引的方法是:

In [121]: t[1, [(0,0),(1,1)], [1,2]]
Out[121]: 
array([[ 7,  8],
       [10, 11]])
或(使用广播)

这实际上可能更接近您想要的,因为它可以推广到索引数组是一些任意列表的情况,如
[1,5,9,10]

In [157]: t = np.arange(2*2*11).reshape(2,2,11)

In [158]: t[1, [[0],[1]], [1,5,9,10]]
Out[158]: 
array([[23, 27, 31, 32],
       [34, 38, 42, 43]])
同样的规则也适用于

In [101]: t[:, :, [1, 2]][1]
Out[101]: 
array([[ 7,  8],
       [10, 11]])
首先请注意,
t[:,:,[1,2]]
的形状将是(2,2,2)。结果将是基本切片的串联

In [102]: t[:, :, 1]
Out[102]: 
array([[ 1,  4],
       [ 7, 10]])

In [103]: t[:, :, 2]
Out[103]: 
array([[ 2,  5],
       [ 8, 11]])
因此,当您运行结果的最后一个(即第三个)轴时,您将得到数组
数组([[1,4],[7,10]])
数组([[2,5],[8,11]])


这不是花哨的索引,这是。尝试
t[1,:,1:3]
@AshwiniChaudhary实际上,这是一种奇特的索引,因为在我的应用程序中,数组
[1,2]
实际上是
[1,5,9,10]
,正如您所看到的,它不是顺序的。我已经在“最小工作示例”中降低了问题的复杂性(因此可以用正常的顺序索引表示法来回答),但这并没有消除问题是使用花式索引的事实。@user89,对不起,我不确定。我猜
t[1,:,(1,2)]
的解释方式与
t[(1,1)的解释方式相同,:,(1,2)]
。也就是说,索引
t[1,:,1]
然后
t[1,:,2]
并沿第一个轴连接它们。使用索引数组时,这种行为更直观(即,
t[arr]
其中arr[0]是轴0索引,arr[1]是轴1索引,依此类推)。
In [101]: t[:, :, [1, 2]][1]
Out[101]: 
array([[ 7,  8],
       [10, 11]])
In [102]: t[:, :, 1]
Out[102]: 
array([[ 1,  4],
       [ 7, 10]])

In [103]: t[:, :, 2]
Out[103]: 
array([[ 2,  5],
       [ 8, 11]])
In [107]: np.allclose(t[:, :, [1,2]], np.dstack([np.array([[ 1,  4], [ 7, 10]]), np.array([[ 2,  5], [ 8, 11]])]))
Out[107]: True