以下代码段
x = np.ones((10,10,10)) x = x[2,:,[2,3,7]] print(x.shape)
结果是x.shape = (3,10)而不是(10,3)。如何使用列表索引第三维以获得形状(10,3)?
x.shape = (3,10)
(10,3)
rlcwz9us1#
我认为strides和base给予了一些额外的见解,如果不是一个实际的解释。制作3D阵列:
strides
base
In [77]: x = np.arange(24).reshape(2,3,4); x.shape, x.strides Out[77]: ((2, 3, 4), (48, 16, 4))
中间的薄片使“怪异”的形状:
In [78]: y = x[1,:,[1,2]]; y.shape, y.strides Out[78]: ((2, 3), (12, 4)) In [79]: y Out[79]: array([[13, 17, 21], [14, 18, 22]])
y是一个副本(自己的基础),并且步幅对于该形状是正常的。现在尝试两步索引,给出预期的形状:
y
In [80]: z = x[1][:,[1,2]]; z.shape, z.strides Out[80]: ((3, 2), (4, 12))
步幅是“反向的”,我们从转置中得到的。
In [81]: z Out[81]: array([[13, 14], [17, 18], [21, 22]])
事实上,它的base是相同的y数组。
In [82]: z.base Out[82]: array([[13, 17, 21], [14, 18, 22]])
列的高级索引(对于2d数组)产生这个转置view。y的情况看起来很像[:,[1,2]]的索引,但不能(出于某种原因)执行我们在z中看到的转置。完整播出版本:
view
[:,[1,2]]
z
In [87]: w = x[1,np.arange(3)[:,None],[1,2]]; w.shape, w.strides Out[87]: ((3, 2), (8, 4)) In [88]: w Out[88]: array([[13, 14], [17, 18], [21, 22]])
其形状和值为z,但跨距不同。如果我们将第一个标量索引替换为一个切片:
In [103]: u = x[1:2,:,[1,2]][0]; u.shape, u.strides Out[103]: ((3, 2), (4, 12)) In [104]: u.base Out[104]: array([[[13, 17, 21]], [[14, 18, 22]]]) In [105]: u.base.shape Out[105]: (2, 1, 3)
注意,第三维[1,2]索引是第一个,正如在“中间切片”的情况中一样;它把基数(2,1,3)转换成(1,3,2),我把它简化成(3,2)
y3bcpkx12#
NB:我将您的数组更改为x = np.arange(125).reshape((5, 5, 5)),并将索引/切片调整为y = x[2, :, [0, 2, 4]],以便更容易地看到它被选中。
x = np.arange(125).reshape((5, 5, 5))
y = x[2, :, [0, 2, 4]]
TL;DR您可以转置结果,或者将第一个轴上的索引表示为一个切片,然后挤压该结果:
>>> x[2, :, [0, 2, 4]].T array([[50, 52, 54], [55, 57, 59], [60, 62, 64], [65, 67, 69], [70, 72, 74]]) >>> x[2:3, :, [0, 2, 4]].squeeze() array([[50, 52, 54], [55, 57, 59], [60, 62, 64], [65, 67, 69], [70, 72, 74]])
我认为一个更有趣的问题是“为什么”会发生这种情况。很长一段时间以来,我把它内化为“numpy有时候会做一些奇怪的事情,记住它就行了”,但它确实有一个解释,你可以应用到任何一般情况下。从链接@Chrysophylaxs共享,结合高级和基本索引是通过第一个切片,然后高级索引来处理的。如果你在这里这样做,你会得到:
>>> x[2, :] array([[50, 51, 52, 53, 54], [55, 56, 57, 58, 59], [60, 61, 62, 63, 64], [65, 66, 67, 68, 69], [70, 71, 72, 73, 74]]) >>> x[2, :][:, [0, 2, 4]] array([[50, 52, 54], [55, 57, 59], [60, 62, 64], [65, 67, 69], [70, 72, 74]])
它的形状是(5, 3),正如我们所料。然而,这并不是numpy正在做的事情,正如那个链接中提到的,当一个维度上的单个索引被请求为另一个维度上的高级索引时,这个单个索引被视为高级索引,而不是一个切片。指标组合有两种情况需要区分:
(5, 3)
当情况是这样时,由高级索引操作产生的维在结果数组中排在的前面,子空间维在其后。由高级索引操作得到的维度是(1, 3)(3,)(标量索引2不提供维度,列表索引[0, 2, 4]提供一个维度,大小为3)感谢@Mad Physicist和@Chrysophylaxs的澄清,这就是为什么我们得到(3, 5)数组(你得到(3, 10)数组)
(1, 3)
(3,)
2
[0, 2, 4]
(3, 5)
(3, 10)
>>> x[2, :, [0, 2, 4]] array([[50, 55, 60, 65, 70], [52, 57, 62, 67, 72], [54, 59, 64, 69, 74]])
如果使用类似的高级索引操作,在第一维上使用 * 两个 * 索引,则会得到形状为(2, 3, 5)的结果:
(2, 3, 5)
>>> x[[[2], [3]], :, [0, 2, 4]] array([[[50, 55, 60, 65, 70], [52, 57, 62, 67, 72], [54, 59, 64, 69, 74]], [[75, 80, 85, 90, 95], [77, 82, 87, 92, 97], [79, 84, 89, 94, 99]]]) >>> x[[[2], [3]], :, [0, 2, 4]].shape (2, 3, 5)
要得到一个(5, 3)数组(或者在您的例子中是(10, 3)数组),将第一个索引改为一个 slice,然后挤压结果,这允许numpy切换回第一个例子,在这里切片是在高级索引之前完成的。
(10, 3)
>>> x[2:3, :, [0, 2, 4]] # (1, 5, 3) array([[[50, 52, 54], [55, 57, 59], [60, 62, 64], [65, 67, 69], [70, 72, 74]]]) >>> x[2:3, :, [0, 2, 4]].squeeze() array([[50, 52, 54], [55, 57, 59], [60, 62, 64], [65, 67, 69], [70, 72, 74]])
或者,只是转置(或移动/交换轴)的结果,你从你的常规索引:
>>> x[2, :, [0, 2, 4]].T array([[50, 52, 54], [55, 57, 59], [60, 62, 64], [65, 67, 69], [70, 72, 74]])
2条答案
按热度按时间rlcwz9us1#
我认为
strides
和base
给予了一些额外的见解,如果不是一个实际的解释。制作3D阵列:
中间的薄片使“怪异”的形状:
y
是一个副本(自己的基础),并且步幅对于该形状是正常的。现在尝试两步索引,给出预期的形状:
步幅是“反向的”,我们从转置中得到的。
事实上,它的
base
是相同的y
数组。列的高级索引(对于2d数组)产生这个转置
view
。y
的情况看起来很像[:,[1,2]]
的索引,但不能(出于某种原因)执行我们在z
中看到的转置。完整播出版本:
其形状和值为
z
,但跨距不同。如果我们将第一个标量索引替换为一个切片:
注意,第三维[1,2]索引是第一个,正如在“中间切片”的情况中一样;它把基数(2,1,3)转换成(1,3,2),我把它简化成(3,2)
y3bcpkx12#
NB:我将您的数组更改为
x = np.arange(125).reshape((5, 5, 5))
,并将索引/切片调整为y = x[2, :, [0, 2, 4]]
,以便更容易地看到它被选中。TL;DR您可以转置结果,或者将第一个轴上的索引表示为一个切片,然后挤压该结果:
我认为一个更有趣的问题是“为什么”会发生这种情况。很长一段时间以来,我把它内化为“numpy有时候会做一些奇怪的事情,记住它就行了”,但它确实有一个解释,你可以应用到任何一般情况下。从链接@Chrysophylaxs共享,结合高级和基本索引是通过第一个切片,然后高级索引来处理的。如果你在这里这样做,你会得到:
它的形状是
(5, 3)
,正如我们所料。然而,这并不是numpy正在做的事情,正如那个链接中提到的,当一个维度上的单个索引被请求为另一个维度上的高级索引时,这个单个索引被视为高级索引,而不是一个切片。
指标组合有两种情况需要区分:
当情况是这样时,
由高级索引操作产生的维在结果数组中排在的前面,子空间维在其后。
由高级索引操作得到的维度是
(1, 3)
(3,)
(标量索引2
不提供维度,列表索引[0, 2, 4]
提供一个维度,大小为3)感谢@Mad Physicist和@Chrysophylaxs的澄清,这就是为什么我们得到(3, 5)
数组(你得到(3, 10)
数组)如果使用类似的高级索引操作,在第一维上使用 * 两个 * 索引,则会得到形状为
(2, 3, 5)
的结果:要得到一个
(5, 3)
数组(或者在您的例子中是(10, 3)
数组),将第一个索引改为一个 slice,然后挤压结果,这允许numpy切换回第一个例子,在这里切片是在高级索引之前完成的。或者,只是转置(或移动/交换轴)的结果,你从你的常规索引: