在 NumPy ndarray 中混合基本索引和高级索引获得的数组形状

Shapes of arrays obtained by mixed basic and advanced indexing in NumPy ndarray

提问人:Locutus 提问时间:8/13/2023 最后编辑:SidLocutus 更新时间:8/13/2023 访问量:49

问:

代码如下:

import numpy as np

x = np.arange(2*32*32*8*16)
x = x.reshape(2, 32, 32, 8, 16)

print("x-shape=", x.shape)

y = x[0, 3:5, 8:10, [1, 2, 3, 4, 5], :]
z = x[0][3:5, 8:10, [1, 2, 3, 4, 5], :]

print("y-shape=", y.shape)
print("z-shape=", z.shape)

和输出:

x-shape= (2, 32, 32, 8, 16)
y-shape= (5, 2, 2, 16)
z-shape= (2, 2, 5, 16)

我希望数组 y 和 z 的形状相等,但事实并非如此。我需要的实际上是 z 的形状。
有人可以解释或指出我的标准吗?
谢谢!

python 数组 numpy 索引 切片

评论

1赞 hpaulj 8/13/2023
y混合了基本(切片)和高级索引,切片位于中间。高级维度 5 放在首位。这很尴尬,但有记录(偶尔会出现在 SO 上)。

答:

0赞 Luatic 8/13/2023 #1

请参阅有关索引的 numpy 文档

单元素索引的工作方式与其他标准 Python 序列的工作方式完全相同。它从 0 开始,接受从数组末尾开始索引的负索引。[...]请注意,如果索引数少于维度的多维数组编制索引,则会得到一个子维数组。

从而得到 的第一个多维子数组。 将有形状.然后,再次对此进行切片,使用多维切片,切片数量与维度一样多。您将获得一个相同维度的数组,其中所有维度都已切片:将前 32 个投影为 2 (5 - 3),将第二个 32 投影为 2 以及 (10 - 8),将 8 投影到 5(选择索引 1 - 5),并将 16 保留为 16 ()。你得到.x[0]xx[0](32, 32, 8, 16)[3:5, 8:10, [1, 2, 3, 4, 5], :]:(2, 2, 5, 16)

这里可能让您感到困惑的是,高级索引规则(更糟糕的是,您结合了高级索引和基本索引)适用,因为您的一个切片是 .因此,numpy 不会创建一个视图,而是一个副本。如果改用正确的切片,则高级索引将不适用,并且将按预期进行。[1, 2, 3, 4, 5]1:6y.shape(2, 2, 5, 16)

这样做的原因是视图(“胖指针”)和高级索引之间存在根本区别:使用高级索引时,您不必使用具有恒定差异的连续范围(算术级数)。您可以使用质数,您最喜欢的数字,无论用于索引。因此,由指针和形状组成的简单视图(它告诉您在每个方向上移动一个指针时如何移动指针,以及数组的结束位置)是不够的。 实际上需要浏览您的索引列表并选择您想要的索引,创建一个新数组。numpy

评论

1赞 hpaulj 8/13/2023
之所以具有不同的形状,与查看与复制无关。它更深入地介绍了高级索引是如何完成的 - 在编译的代码中。y
1赞 hpaulj 8/13/2023 #2

您的阵列:

In [24]: x.shape
Out[24]: (2, 32, 32, 8, 16)

In [25]: y=x[0,:,:,:,[1,2,3,4,5]]
In [26]: y.shape
Out[26]: (5, 32, 32, 8)

让我们尝试不使用首字母 0,即没有“中间”切片:y

In [27]: z=x[:,:,:,:,[1,2,3,4,5]]    
In [28]: z.shape
Out[28]: (2, 32, 32, 8, 5)

y是一个副本,它自己的“基础”:

In [29]: y.base

但是是另一个数组的转置。请注意,维度是第一位的:z5

In [30]: z.base.shape
Out[30]: (5, 2, 32, 32, 8)

高级索引生成副本,然后转置以按正确的顺序获取索引这一事实没有记录。但我怀疑这是意想不到的混合基本/高级形状的关键。

我们也在大步前进中看到了这一点:

In [34]: x.strides
Out[34]: (1048576, 32768, 1024, 128, 8)
In [35]: y.strides
Out[35]: (65536, 2048, 64, 8)
In [36]: z.base.strides
Out[36]: (131072, 65536, 2048, 64, 8)
In [37]: z.strides
Out[37]: (65536, 2048, 64, 8, 131072)

初始索引为 ,混合文档所谈论的并不明显。如果我们尝试从中选择“对角线”,则更是如此。尺寸 2 维度应该是第一个还是最后一个?0ambiguityx

In [54]: z = x[[1,0],:,:,:,[1,2]]
In [55]: z.shape
Out[55]: (2, 32, 32, 8)