NumPy 2.x 完全指南【三十】整数数组索引
文章目录
- 1. 高级索引
- 2. 整数数组索引(花式索引)
- 2.1 一维数组
- 2.2 二维数组
- 2.2.1 部分索引
- 2.1.2 全索引
- 2.3 三维数组
- 2.3.1 部分索引
- 2.3.1 全索引
1. 高级索引
在 NumPy
中,高级索引允许通过非连续的、复杂的规则选择数组中的元素,支持以下两种类型:
- 整数数组索引
- 布尔数组索引
注意事项:
- 高级索引总是返回数据的副本(
copy
)而非视图(切片返回视图)。 - 当索引对象满足以下任一条件时,才会触发高级索引:
- 非元组的序列对象:如列表(
list
)或嵌套列表。 - 整数或布尔类型的
ndarray
:数组元素为整数或布尔值。 - 包含至少一个序列或
ndarray
的元组:元组中存在列表、数组等非标量索引对象。
- 非元组的序列对象:如列表(
示例,x[(1, 2, 3)]
的索引对象是一个元组,不满足上面任一条件,是一个普通索引等价于 x[1, 2, 3]
,表示取第 2
层 3
行 4
位置的元素:
arr = np.arange(64).reshape(4, 4, 4)
print(arr)# 基本索引示例
result = arr[(1, 2, 3)]
print(result) # 输出:27# 等效于
result_basic = arr[1, 2, 3]
print(result_basic) # 同样输出:27
而 x[(1, 2, 3),]
中有一个逗号,元组中包含元组,符合了包含至少一个序列的元组的条件,属于高级索引对象。
2. 整数数组索引(花式索引)
定义:通过整数数组指定要访问元素的索引位置。
假设数组的形状为 (d1
, d2
, …, dn
),整数数组索引的基本表达式为:
# index_1, index_2,...:索引对象,作用于对应的维度
arr[index_1, index_2, ..., index_k]
核心规则:
- 维度填充:索引对象数量
<
数组维度→
缺失维度自动补:
。 - 索引数组的配对与广播:
- 所有索引数组会先广播到相同形状(如果可以)。
- 广播后的索引数组中的每个元素(按位置)组合成一个坐标元组,用于索引原始数组。
- 输出形状:
- 全索引(索引数组数量
=
数组维度):输出形状=
广播后的索引数组形状。 - 部分索引(索引数组数量
<
数组维度):输出形状=
广播后的索引数组形状+
剩余维度的完整大小。
- 全索引(索引数组数量
2.1 一维数组
一维数组只有一个轴,维度数也是一,索引表达式为 arr[index]
,所以不涉及维度填充,也不涉及部分索引。结果数组的形状完全和索引数组对象的形状一致,因为索引值对应的是标量元素。
示例 1 ,索引对象为一维数组时,结果数组的形状和索引对象一致,然后将对应索引位置的元素映射到结果数组中:
# 创建基础一维数组
arr = np.arange(10, 0, -1) # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
"""
索引:0 1 2 3 4 5 6 7 8 9
值: 10 9 8 7 6 5 4 3 2 1
"""# 索引对象
index_arr = [2, 4, 5]
# 获取 arr 在 [2, 4, 5] 索引处的元素
print(arr[index_arr]) # [8 6 5]# 获取 arr 在 [-2, 1, 6] 索引处的元素(包含负索引)
print(arr[np.array([-2, 1, 6])]) # [2 9 4]
执行过程如下所示:
如果索引值越界,会抛出 IndexError
异常:
# 索引对象为 ndarray
index_arr = np.array([1, 4, 20])
# 获取 arr 在 [1, 4, 20] 索引处的元素
print(arr[index_arr]) # IndexError: index 20 is out of bounds for axis 0 with size 10
示例 2 ,索引对象为二维数组时,也是一样的执行流程:
# 索引对象 (2,3)
index_arr = np.array([[1, 2, 3],[4, 5, 6]])
print(arr[index_arr])
# [[9 8 7]
# [6 5 4]]
执行过程如下所示:
示例 3 ,索引对象为三维或更高维度的数组时,也是同样的执行流程:
# 索引对象 (2, 2, 3)
index_arr = np.array([[[1, 0, 2],[2, 1, 0]],[[1, 2, 3],[2, 3, 3]]])
print(arr[index_arr])
# [[[ 9 10 8]
# [ 8 9 10]]
# [[ 9 8 7]
# [ 8 7 7]]]
2.2 二维数组
二维数组有两个轴,高级索引表达式可以有以下几种形式:
arr[index1,index2]
(全索引)。arr[index1]
(部分索引)。
2.2.1 部分索引
arr[index1]
(部分索引):仅作用于轴 0
(行),默认轴 1
完全保留,等效于arr[index, :]
。
示例 1 ,单个一维的索引对象时,每个索引值映射到哪一行:
# 二维数组
arr = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])# 一维索引数组
# 0:第一行
# 2:第三行
index = [0, 2]
result = arr[index]
print(result)
# [[1 2 3]
# [7 8 9]]
示例 2 ,索引对象为二维数组使用 arr[index]
时,每个索引值也表示哪一行,然后填充到结果数组中:
# 二维数组
arr = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])# 二维索引数组
index = [[0, 1], [1, 2]]
# 结果:
# [[0 行, 1 行], [1 行 , 2 行]]
result = arr[index]
print(result)
# [[[1 2 3]
# [4 5 6]]
#
# [[4 5 6]
# [7 8 9]]]
示例 3 ,索引对象为更高维度数组时,arr[index]
也是一样:
# 三维索引数组
index = [[[0, 1], [1, 2]]]
# 结果:
# [[[0 行, 1 行], [1 行 , 2 行]]]
result = arr[index]
print(result)
# [[[[1 2 3]
# [4 5 6]]
#
# [[4 5 6]
# [7 8 9]]]]
2.1.2 全索引
arr[index1,index2]
(全索引) :同时作用于轴 0
(行)和轴 1
(列)。
示例 1 ,多个相同形状的一维的索引对象时,会直接进行索引配对,将索引数组中的每个元素(按位置)组合成一个坐标元组,然后根据坐标获取到对应元素进行填充:
index1 = [0, 2] # 行索引
index2 = [1, 1] # 列索引
# 配对:[(0,1),(2,1)]
result = arr[index1, index2]
print(result)
# [2 8]
示例 2 ,当多不同形状的一维的索引对象时,无法进行一一配对,会尝试进行广播,如果它们的长度不一样,且其中一个的长度不为 1
,无法满足广播条件引发错误:
index1 = [0, 2] # 行索引
index2 = [1, 1, 1] # 列索引
result = arr[index1, index2]
# IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (2,) (3,)
示例 3 ,满足广播机制时,index2
会被广播为 [0,0]
,然后再进行索引配对:
index1 = [0, 2] # 行索引
index2 = [0] # 列索引 广播为 `[0,0]`
# 第一组索引:(0, 0) -> 行 0 列 1 的元素是 1
# 第二组索引:(2, 0) -> 行 2 列 0 的元素是 7
result = arr[index1, index2]
print(result) # [1 7]
示例 4 ,对更高维度的索引对象,也会先进行广播,然后配对映射,再将索引对应位置的元素填充到结果数组:
# 创建行索引和列索引
row_idx = np.array([[0, 1],[1, 2]])
col_idx = np.array([[1, 1],[2, 2]])# 配对:
# [[(0 行 1 列 ), (1 行 1 列)],
# [(1 行 2 列), (2 行 2 列)]]# 同时索引行和列
result = arr[row_idx, col_idx]
print(result)
# [[2 5]
# [6 9]]
2.3 三维数组
三维或者更好维度的数组,其索引规则也是一样,比如三维数组索引表达式可以有以下几种形式:
arr[index1,index2,index3]
(全索引):同时作用于所有轴。arr[index1,index2]
(部分索引):等效于arr[index1,index2, :]
。arr[index1]
(部分索引):等效于arr[index1,:, :]
。
2.3.1 部分索引
示例 1 ,arr[index1]
不涉及索引配对,每个索引只作用于 0
轴,每个索引对应的结果为子数组(二维)。这里索引对象是一维的,索引值对应的结果是二维的,所以填充返回的结果是三维的(1+2
):
# 创建一个 3 x 3 x 3三维数组
arr = np.arange(27).reshape(3, 3, 3)
"""
arr_3d 结构:
第一层: [[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8]]第二层: [[ 9, 10, 11],[12, 13, 14],[15, 16, 17]]第三层: [[18, 19, 20],[21, 22, 23],[24, 25, 26]]
"""
# [0 层, 1 层]=》 结果为三维数组
index1 = np.array([0, 1])result = arr[index1]
# 等效于 arr[index1, :, :]
print(result)
# [[[ 0 1 2]
# [ 3 4 5]
# [ 6 7 8]]
#
# [[ 9 10 11]
# [12 13 14]
# [15 16 17]]]
示例 2 ,arr[index1,index2]
获取到行并填充到结果数组:
index1 = np.array([0, 1])
index2 = np.array([1, 2])
# 配对:
# [(0 层 1 行 ),(1 层 2 行)]result = arr[index1,index2]
print(result)
# [[ 3 4 5]
# [15 16 17]]
示例 3 ,arr[index]
形式下的二维索引对象:
# 二维索引数组
index = [[0, 1], [1, 2]]
# 结果:
# [[0 层, 1 层], [1 层 , 2 层]]
result = arr[index]
print(result)
# [[[[ 0 1 2]
# [ 3 4 5]
# [ 6 7 8]]
#
# [[ 9 10 11]
# [12 13 14]
# [15 16 17]]]
#
#
# [[[ 9 10 11]
# [12 13 14]
# [15 16 17]]
#
# [[18 19 20]
# [21 22 23]
# [24 25 26]]]]
示例 4 ,arr[index]
形式下的三维索引对象:
# 二维索引数组
index = [[[0, 1], [1, 2]],[[1, 1], [1, 2]]]
# 结果:
# [[[0 层 , 1 层], [1 层, 2 层]],
# [[1 层, 1 层 ], [1 层, 2 层]]]
result = arr[index]
print(result)
# [[[[[ 0 1 2]
# [ 3 4 5]
# [ 6 7 8]]
#
# [[ 9 10 11]
# [12 13 14]
# [15 16 17]]]
#
#
# [[[ 9 10 11]
# [12 13 14]
# [15 16 17]]
#
# [[18 19 20]
# [21 22 23]
# [24 25 26]]]]
#
#
#
# [[[[ 9 10 11]
# [12 13 14]
# [15 16 17]]
#
# [[ 9 10 11]
# [12 13 14]
# [15 16 17]]]
#
#
# [[[ 9 10 11]
# [12 13 14]
# [15 16 17]]
#
# [[18 19 20]
# [21 22 23]
# [24 25 26]]]]]
示例 5 ,arr[index1,index2]
形式下的二维索引对象:
index1 = np.array([[0, 1],[0, 1]])
index2 = np.array([[0, 2],[0, 2]])# 配对:
# [[(0 层 0 行 ),(1 层 2 行)]
# ,[(0 层 0 行 ),(1 层 2 行)]]result = arr[index1,index2]
print(result)
# [[[ 0 1 2]
# [15 16 17]]
#
# [[ 0 1 2]
# [15 16 17]]]
2.3.1 全索引
示例 1 ,arr[index1,index2,index3]
形式时也会进行广播机制 +
索引配对,获取单个元素并填充到结果数组:
index1 = np.array([0, 1])
index2 = np.array([1, 2])
index3 = np.array([1, 1])
# 配对:
# [(0 层 1 行 1 列),(1 层 2 行 1 列)]result = arr[index1,index2,index3]
print(result)
# [4 16]