NumPy 高级索引
在 NumPy 中,高级索引(Advanced Indexing)是 ndarray
(N 维数组)的一种强大功能,允许通过整数数组、布尔数组或其他复杂方式访问或修改数组的元素或子数组。相比基本索引和切片,高级索引提供了更灵活的数据筛选和操作方式,广泛应用于数据分析、机器学习和科学计算。以下是对 NumPy 高级索引的详细中文讲解,涵盖定义、类型、示例、注意事项及最佳实践,帮助你全面掌握高级索引的使用。
一、NumPy 高级索引概述
1. 什么是高级索引?
- 定义:高级索引是指使用整数数组、布尔数组或其他非基本切片(如
start:stop:step
)的方式访问或修改ndarray
的元素或子数组。 - 特点:
- 灵活性:支持非连续索引、条件筛选和复杂模式。
- 副本操作:高级索引通常返回数据副本(而非视图)。
- 多维支持:适用于任意维度的数组。
- 用途:
- 筛选符合条件的数据(如值大于某阈值)。
- 提取特定位置的元素(如随机抽样)。
- 批量修改数组的非连续部分。
2. 高级索引 vs 基本索引
特性 | 高级索引 | 基本索引/切片 |
---|---|---|
方式 | 整数数组、布尔数组 | 单一索引、切片(如 arr[1:3] ) |
返回类型 | 通常返回副本 | 通常返回视图 |
灵活性 | 支持复杂模式(如条件筛选) | 局限于连续范围 |
性能 | 可能更慢(因副本) | 更快(视图操作) |
3. 高级索引的类型
- 整数数组索引:使用整数数组指定要访问的元素位置。
- 布尔数组索引:使用布尔数组筛选符合条件的元素。
- 混合索引:结合整数、布尔或切片进行操作。
二、高级索引的类型与用法
以下详细讲解高级索引的两种主要方式及混合使用。
1. 整数数组索引
- 描述:使用整数数组(或列表)指定要访问的元素索引,允许非连续或重复选择。
- 语法:
arr[indices]
或arr[indices_dim1, indices_dim2, ...]
- 特点:
- 索引数组的形状决定输出数组的形状。
- 返回副本,修改不影响原数组。
- 示例(一维数组):
import numpy as np
arr = np.array([10, 20, 30, 40, 50])
indices = [0, 2, 4]
print(arr[indices]) # 输出:[10 30 50]
- 示例(二维数组):
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
row_indices = [0, 2]
col_indices = [1, 0]
print(arr[row_indices, col_indices]) # 输出:[2 7](选择 (0,1) 和 (2,0))
- 多维输出:
row_indices = np.array([[0, 0], [2, 2]])
col_indices = np.array([[1, 2], [0, 1]])
print(arr[row_indices, col_indices]) # 输出:
# [[2 3]
# [7 8]]
- 重复索引:
indices = [0, 0, 2]
print(arr[indices, 1]) # 输出:[2 2 8](重复选择第 0 行)
2. 布尔数组索引
- 描述:使用布尔数组(
True
/False
)筛选符合条件的元素。 - 语法:
arr[boolean_mask]
- 特点:
- 布尔数组形状需与被索引的维度匹配。
- 返回副本,修改不影响原数组。
- 常用于条件筛选。
- 示例(一维数组):
arr = np.array([1, 2, 3, 4, 5])
mask = arr > 2
print(mask) # 输出:[False False True True True]
print(arr[mask]) # 输出:[3 4 5]
- 示例(二维数组):
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
mask = arr > 5
print(mask) # 输出:[[False False False] [False False True] [True True True]]
print(arr[mask]) # 输出:[6 7 8 9]
- 条件组合:
mask = (arr > 2) & (arr < 7)
print(arr[mask]) # 输出:[3 4 5 6]
3. 混合索引
- 描述:结合基本索引、切片和高级索引。
- 示例:
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr[0:2, [0, 2]]) # 输出:
# [[1 3]
# [4 6]]
- 布尔与切片:
mask = arr[:, 0] > 2
print(arr[mask, 1:]) # 输出:[[8 9]](第 0 列 > 2 的行,提取后两列)
三、修改数组元素
高级索引可用于修改符合条件的元素。
- 整数数组修改:
arr = np.array([10, 20, 30, 40, 50])
indices = [1, 3]
arr[indices] = 0
print(arr) # 输出:[10 0 30 0 50]
- 布尔数组修改:
arr = np.array([1, 2, 3, 4, 5])
arr[arr > 3] = 0
print(arr) # 输出:[1 2 3 0 0]
四、实际应用场景
1. 数据筛选
筛选大于均值的元素:
arr = np.array([1, 2, 3, 4, 5])
mean = np.mean(arr)
print(arr[arr > mean]) # 输出:[4 5]
2. 随机抽样
随机选择 3 个元素:
arr = np.array([10, 20, 30, 40, 50])
indices = np.random.choice(len(arr), 3, replace=False)
print(arr[indices]) # 输出:随机 3 个元素
3. 矩阵子集提取
提取特定行列的元素:
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
rows = [0, 2]
cols = [0, 2]
print(arr[rows, cols]) # 输出:[1 9]
4. 数据清洗
将异常值替换为均值:
arr = np.array([1, 2, 100, 4, 5])
arr[arr > 10] = np.mean(arr)
print(arr) # 输出:[1. 2. 22.4 4. 5.]
五、注意事项
- 副本 vs 视图:
- 高级索引(整数数组、布尔索引)返回副本,修改不影响原数组:
python arr = np.array([1, 2, 3]) subset = arr[[0, 2]] subset[0] = 10 print(arr) # 输出:[1 2 3]
- 基本切片返回视图,需小心修改:
python view = arr[0:2] view[0] = 10 print(arr) # 输出:[10 2 3]
- 形状匹配:
- 布尔索引的形状需与被索引维度匹配:
python arr = np.array([[1, 2], [3, 4]]) mask = np.array([True, False]) print(arr[mask]) # 输出:[[1 2]]
- 性能开销:
- 高级索引生成副本,内存和计算开销较大。
- 大数组优先使用切片(视图)优化性能。
- 索引越界:
- 整数数组索引超出范围会抛出
IndexError
:python arr = np.array([1, 2, 3]) # arr[[0, 5]] # 报错:IndexError
- 布尔条件复杂性:
- 使用
&
(与)、|
(或)、~
(非)组合条件,需加括号:python arr = np.array([1, 2, 3, 4]) mask = (arr > 1) & (arr < 4) print(arr[mask]) # 输出:[2 3]
六、最佳实践
- 优先切片优化性能:
- 若需求可通过切片实现,避免高级索引:
python arr = np.array([1, 2, 3, 4]) print(arr[1:3]) # 视图,高效
- 明确副本需求:
- 需要独立数据时,使用高级索引或
copy()
:python subset = arr[[0, 2]].copy()
- 布尔索引简化筛选:
- 使用布尔索引处理复杂条件:
python arr = np.array([1, 2, 3, 4]) print(arr[arr % 2 == 0]) # 输出:[2 4]
- 检查形状:
- 索引前确认数组和索引形状:
python print(arr.shape, mask.shape)
- 优化大数组:
- 避免频繁高级索引,使用
np.where
替代:python arr = np.array([1, 2, 3, 4]) indices = np.where(arr > 2)[0] print(arr[indices]) # 输出:[3 4]
- 结合其他库:
- 与 Pandas 集成处理数据:
python import pandas as pd df = pd.DataFrame(arr) print(df[df[0] > 2]) # Pandas 布尔索引
七、总结
NumPy 的高级索引(整数数组索引和布尔数组索引)提供了灵活的数组访问和修改方式,适合条件筛选、随机抽样和复杂数据提取。高级索引通常返回副本,需注意内存开销和性能影响。掌握整数数组索引(选择特定位置)、布尔索引(条件筛选)及混合索引,结合最佳实践(如优先切片、检查形状、优化性能),能高效处理数组数据。
如果你需要更复杂的示例(如多维高级索引、性能优化)或特定场景的代码,请告诉我!