为何Numpy切片与花式索引返回不同形状?含具体案例疑问
Numpy切片与花式索引的形状差异解析
对以下两种Numpy索引场景的返回形状存在疑惑,尤其不解x[:, [1], :, [1]]的形状为何是(1, 2, 2)——维度0用切片:本应保留原维度值2,想明确该形状的确定逻辑。
测试代码
import numpy as np x = np.arange(2 * 2 * 2 * 2).reshape((2, 2, 2, 2)) print(f"x:\n{x}") a = x[:, [1], [1], :] print("==================") print(f"shape of x[:, [1], [1], :] == {a.shape}") print(a) print("==================") b = x[:, [1], :, [1]] print(f"shape of x[:, [1], :, [1]] == {b.shape}") print(b)
运行结果
x: [[[[ 0 1] [ 2 3]] [[ 4 5] [ 6 7]]] [[[ 8 9] [10 11]] [[12 13] [14 15]]]] ================== shape of x[:, [1], [1], :] == (2, 1, 2) [[[ 6 7]] [[14 15]]] ================== shape of x[:, [1], :, [1]] == (1, 2, 2) [[[ 5 7] [13 15]]]
核心规则:花式索引的广播机制
Numpy中,切片:仅保留原维度结构,但花式索引(用列表/数组索引)会触发广播机制——当多个维度同时使用花式索引时,所有索引数组会被广播到共同的形状,最终结果的形状就是这个广播后的形状。切片:会被自动转换为对应维度的全索引数组,参与广播计算。
案例1:x[:, [1], [1], :]的形状解析
各维度的索引类型与对应数组:
- 维度0:
:→ 等价于索引数组[0,1],形状(2,) - 维度1:
[1]→ 索引数组,形状(1,) - 维度2:
[1]→ 索引数组,形状(1,) - 维度3:
:→ 等价于索引数组[0,1],形状(2,)
广播过程:
所有索引数组会被扩展到共同的形状(2,1,2):
- 维度0的
(2,)扩展为(2,1,2) - 维度1、2的
(1,)广播为(2,1,2) - 维度3的
(2,)扩展为(2,1,2)
最终结果形状为(2,1,2),对应每个维度0的元素,取维度1=1、维度2=1的位置,再保留维度3的所有元素。
案例2:x[:, [1], :, [1]]的形状解析
各维度的索引类型与对应数组:
- 维度0:
:→ 等价于索引数组[0,1],形状(2,) - 维度1:
[1]→ 索引数组,形状(1,) - 维度2:
:→ 等价于索引数组[0,1],形状(2,) - 维度3:
[1]→ 索引数组,形状(1,)
广播过程:
所有索引数组会被扩展到共同的形状(1,2,2):
- 维度1的
(1,)作为第一个维度,扩展为(1,1,1)后广播到(1,2,2) - 维度0的
(2,)作为第二个维度,扩展为(1,2,1)后广播到(1,2,2) - 维度2的
(2,)作为第三个维度,扩展为(1,1,2)后广播到(1,2,2) - 维度3的
(1,)广播后不新增维度
最终结果形状为(1,2,2),对应取维度1=1、维度3=1的所有组合:每个维度0的元素搭配每个维度2的元素,形成(2,2)的子数组,再被维度1的单元素索引包裹为(1,2,2)的整体形状。
关键总结
- 切片仅保留原维度,不触发广播;花式索引会将索引数组广播到共同形状,结果形状由广播后的形状决定。
- 当花式索引分布在非连续维度时,广播后的形状会重新排列维度顺序,这就是
x[:, [1], :, [1]]中维度0的2没有出现在第一个位置的原因。
内容的提问来源于stack exchange,提问作者Alan
相关产品推荐
相关产品推荐

