NumPy数组是一种基本的数据结构,掌握访问和修改其内容的技巧是必不可少的。与标准的Python列表类似,你经常需要选择数据的特定元素、行、列或子部分。NumPy为此提供了灵活高效的索引和切片机制。这些技术对于机器学习任务中的数据处理是核心,例如选择特征或训练样本。访问单个元素NumPy数组使用零基索引,这意味着第一个元素位于索引0,第二个元素位于索引1,依此类推。一维数组(向量)对于一维数组,你可以通过在方括号 [] 中指定其索引来访问元素。import numpy as np # 创建一个一维数组 vector = np.arange(5, 11) # 创建数组([5, 6, 7, 8, 9, 10]) print("原始向量:", vector) # 访问第一个元素(索引0) first_element = vector[0] print("第一个元素:", first_element) # 输出: 5 # 访问第三个元素(索引2) third_element = vector[2] print("第三个元素:", third_element) # 输出: 7 # 使用负索引访问最后一个元素 last_element = vector[-1] print("最后一个元素:", last_element) # 输出: 10负索引从数组的末尾开始计数,因此 -1 指的是最后一个元素,-2 指的是倒数第二个元素,依此类推。二维数组(矩阵)对于二维数组(矩阵),你需要同时指定行索引和列索引来访问单个元素。NumPy中标准的方法是使用一对方括号,索引之间用逗号分隔:[行, 列]。# 创建一个二维数组(3行,4列) matrix = np.array([ [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12] ]) print("原始矩阵:\n", matrix) # 访问第0行第1列的元素 element_0_1 = matrix[0, 1] print("元素在 [0, 1]:", element_0_1) # 输出: 2 # 访问第2行第3列的元素 element_2_3 = matrix[2, 3] print("元素在 [2, 3]:", element_2_3) # 输出: 12 # 访问第1行第0列的元素 element_1_0 = matrix[1, 0] print("元素在 [1, 0]:", element_1_0) # 输出: 5虽然你有时可能会看到 matrix[行][列] 这样的表示法,但通常更推荐使用 matrix[行, 列],因为它对于多维数组更高效且语法更清晰。数组切片切片允许你从数组中选择一个元素范围,从而创建一个子数组。语法类似于Python列表切片:开始:结束:步长。请记住,开始 索引是包含的,而 结束 索引是排外的。步长 决定了元素之间的间隔。如果省略,开始 默认为0,结束 默认为数组长度,步长 默认为1。一维数组切片# 创建一个一维数组 vector = np.arange(10, 20) # 创建数组([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]) print("原始向量:", vector) # 获取从索引2开始(包括)到索引5结束(不包括)的元素 slice1 = vector[2:5] print("切片 [2:5]:", slice1) # 输出: [12 13 14] # 获取从开头到索引4(不包括)的元素 slice2 = vector[:4] print("切片 [:4]:", slice2) # 输出: [10 11 12 13] # 获取从索引6到末尾的元素 slice3 = vector[6:] print("切片 [6:]:", slice3) # 输出: [16 17 18 19] # 获取整个数组中每隔一个的元素 slice4 = vector[::2] print("切片 [::2]:", slice4) # 输出: [10 12 14 16 18] # 获取从索引1到索引7(不包括)中每隔一个的元素 slice5 = vector[1:8:2] print("切片 [1:8:2]:", slice5) # 输出: [11 13 15 17]二维数组切片你可以通过为行和列提供切片(用逗号分隔)来沿两个维度对二维数组进行切片:数组[行切片, 列切片]。# 创建一个二维数组(4行,5列) matrix = np.array([ [10, 11, 12, 13, 14], [15, 16, 17, 18, 19], [20, 21, 22, 23, 24], [25, 26, 27, 28, 29] ]) print("原始矩阵:\n", matrix) # 获取前两行(第0行和第1行)和所有列 slice_rows = matrix[0:2, :] # 或 matrix[:2, :] print("前两行:\n", slice_rows) # 输出: # [[10 11 12 13 14] # [15 16 17 18 19]] # 获取所有行,但只取第1列和第2列(索引1到3,不包括3) slice_cols = matrix[:, 1:3] print("第1列和第2列:\n", slice_cols) # 输出: # [[11 12] # [16 17] # [21 22] # [26 27]] # 获取一个子矩阵:第1行和第2行,第2、3、4列 sub_matrix = matrix[1:3, 2:] print("子矩阵(行1-2,列2-末尾):\n", sub_matrix) # 输出: # [[17 18 19] # [22 23 24]] # 获取单行(返回一个一维数组) row_1 = matrix[1, :] # 等同于 matrix[1] print("第1行:", row_1) # 输出: [15 16 17 18 19] # 获取单列(返回一个一维数组) col_3 = matrix[:, 3] print("第3列:", col_3) # 输出: [13 18 23 28]重要:视图与副本NumPy切片的一个重要方面是,基本切片(使用 开始:结束:步长)返回的是原始数组数据的视图,而不是副本。这意味着切片只是以不同方式查看内存中相同底层数据的方法。修改视图中的元素也会修改原始数组。# 创建一个数组 original_array = np.arange(5) # 数组([0, 1, 2, 3, 4]) print("原始数组:", original_array) # 创建一个切片(一个视图) array_slice = original_array[1:4] # 包含元素 [1, 2, 3] 的视图 print("切片(视图):", array_slice) # 修改切片中的一个元素 array_slice[1] = 99 # 修改切片的第二个元素(对应于原始数组的索引2) print("修改后的切片:", array_slice) # 输出: [ 1 99 3] # 查看原始数组的变化 print("切片修改后的原始数组:", original_array) # 输出: [ 0 1 99 3 4]这种行为是为了提高效率而设计的,尤其是在处理大型数据集时,因为它避免了不必要的数据重复。但是,如果你需要一个不影响原始数据的切片数据的独立副本,则必须明确使用 .copy() 方法。# 创建一个数组 original_array = np.arange(5) # 数组([0, 1, 2, 3, 4]) print("原始数组:", original_array) # 创建一个切片的副本 array_copy = original_array[1:4].copy() print("切片(副本):", array_copy) # 修改副本中的一个元素 array_copy[1] = 99 print("修改后的副本:", array_copy) # 输出: [ 1 99 3] # 原始数组保持不变 print("副本修改后的原始数组:", original_array) # 输出: [0 1 2 3 4]高级索引:整数数组和布尔数组NumPy还支持更高级的索引技术。基本切片用于提取连续的块或规则间隔的元素,而整数数组索引和布尔数组索引则允许根据索引列表或条件选择任意元素。整数数组索引(花式索引)你可以使用整数列表或其他NumPy数组作为索引。这让你能够以你选择的任何顺序选取元素、行或列。# 创建一个一维数组 vector = np.array([10, 20, 30, 40, 50, 60]) print("原始向量:", vector) # 选择索引1、3和0处的元素 selected_elements = vector[[1, 3, 0]] print("选择的元素 [1, 3, 0]:", selected_elements) # 输出: [20 40 10] # 创建一个二维数组 matrix = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12] ]) print("原始矩阵:\n", matrix) # 按顺序选择第0、2和1行 selected_rows = matrix[[0, 2, 1], :] # 注意 :,这表示选择这些行的所有列 print("选择的行 [0, 2, 1]:\n", selected_rows) # 输出: # [[1 2 3] # [7 8 9] # [4 5 6]] # 使用索引对(行,列)选择特定元素 selected_cells = matrix[[0, 1, 3], [2, 0, 1]] # 选择 (0,2), (1,0), (3,1) print("选择的特定单元格:", selected_cells) # 输出: [ 3 4 11]与基本切片不同,整数数组索引总是返回数据的副本,而不是视图。布尔数组索引你可以使用布尔数组(包含 True 和 False)来索引数组。这对于根据特定条件选择元素非常有用。布尔数组必须与被索引的维度具有相同的形状。# 创建一个一维数组 data = np.array([1, 5, 2, 8, 3, 7, 4, 6]) print("原始数据:", data) # 创建一个布尔条件:元素大于4 condition = data > 4 print("布尔条件(数据 > 4):", condition) # 输出: [False True False True False True False True] # 选择条件为True的元素 selected_data = data[condition] print("元素 > 4:", selected_data) # 输出: [5 8 7 6] # 你可以更简洁地编写 selected_data_compact = data[data > 4] print("元素 > 4(简洁版):", selected_data_compact) # 输出: [5 8 7 6] # 二维数组示例 matrix = np.array([ [1, 6, 2], [7, 3, 8], [4, 9, 5] ]) print("原始矩阵:\n", matrix) # 选择大于5的元素 selected_matrix_elements = matrix[matrix > 5] print("矩阵元素 > 5:", selected_matrix_elements) # 输出: [6 7 8 9](返回一个展平的一维数组) # 选择第一列元素大于3的行 rows_condition = matrix[:, 0] > 3 # 基于第一列的条件 print("第一列元素 > 3 的行:\n", matrix[rows_condition, :]) # 输出: # [[ 7 3 8] # [ 4 9 5]]与整数数组索引一样,布尔数组索引也返回数据的副本。熟练掌握索引和切片对于有效地在NumPy中处理数据是必要的。这些技术使你能够精确地访问、修改和筛选分析和机器学习模型输入所需的数组元素。