以某种意想不到的方式执行特定切片时,numpy数组的形状正在发生变化
我尝试了几种将同一数组切片的方法,但是细微的差异会导致数组形状的结果不同
import numpy as np
z = np.zeros((1,9,10,2))
# This makes sense
print(z[...,[1,0]].shape)
# (1, 9, 10, 2)
print(z[0,...].shape)
# (9, 10, 2)
print(z[0:1,...,[1,0]].shape)
# (1, 9, 10, 2)
print(z[0][...,[1,0]].shape)
# (9, 10, 2)
# This doesn't, I would expect (9, 10, 2) in both cases
print(z[0,:,:,[1,0]].shape)
# (2, 9, 10)
print(z[0,...,[1,0]].shape)
# (2, 9, 10)
在最后两个示例中,我不明白为什么最后一个轴移动到第一个位置。
我将Python 3.6.4
与numpy 1.15.1
一起使用
答案 0 :(得分:1)
在最后两种情况下可能会发现结果出乎意料的原因是,即使您也使用切片索引,但数组的索引遵循advanced indexing的规则。
有关此行为的详细解释,请检查combining advanced and basic indexing。在这些最后的情况下,您会得到意想不到的结果形状。在文档中,您将看到上述可能导致意外结果的场景之一是:
x[arr1, :, arr2]
。在您的情况下,尽管您仅使用整数沿第一个轴进行索引,但广播该整数并将两个数组都迭代为一个。 在这种情况下,由高级索引操作产生的维数首先出现在结果数组中,然后是子空间维数。
这里的关键是要理解文档中提到的,就像将每个高级索引元素的索引结果连接起来一样。
所以从本质上讲,它的作用是:
z = np.random.random((1,9,10,2))
a = np.concatenate([z[0,:,:,[1]], z[0,:,:,[0]]], axis=0)
b = z[0,:,:,[1,0]]
np.allclose(a,b)
# True
但是...为什么会发生?
其背后的原因是高级索引和基本索引的行为不同,因为它们具有不同的用途。 让我们通过一个例子来阐明这一点:
a = np.random.randint(1,10, (3,3,4))
print(a)
array([[[8, 2, 7, 2],
[3, 1, 2, 4],
[9, 8, 2, 2]],
[[4, 2, 7, 4],
[9, 6, 6, 7],
[4, 2, 5, 1]],
[[7, 4, 2, 3],
[6, 9, 3, 6],
[3, 3, 2, 6]]])
现在说我们想索引a
,以便从前两个2d数组中获取最后两个列。为此,方法是使用basic slicing:
a[:2,:,2:]
array([[[7, 2],
[2, 4],
[2, 2]],
[[7, 4],
[6, 7],
[5, 1]]])
但是,现在,如果我想做同样的事情,而不是选择最后两个列,我希望分别从两个数组中选择第一列和第二列,该怎么办?我该如何处理?为此,我们有了高级索引:
a[[0,1],:,[2,3]]
array([[7, 2, 2],
[4, 7, 1]])
因此,您可以看到两种索引编制方法在本质上是不同的:
整数数组索引允许根据数组的N维索引选择数组中的任意项。每个整数数组代表该维度的多个索引
使用多个高级索引时,高级索引始终会广播并迭代为一个,其中获得的结果具有以下形状:
result[i_1, ..., i_M] == x[ind_1[i_1, ..., i_M], ind_2[i_1, ..., i_M], ind_N[i_1, ..., i_M]]
因此,即使切片包含与数组索引相同数量的轴元素,结果形状也会有所不同。如上所述,这是因为两种索引编制方法都有不同的用途。
但是,如果只有一个高级索引,则不会发生这种情况:
a[:2,:2,[2,3]]
array([[[7, 2],
[2, 4],
[2, 2]],
[[7, 4],
[6, 7],
[5, 1]]])
因为没有其他高级索引可用于广播,因此索引数组充当了沿最后一个轴的切片。