Python numpy索引与切片完整代码示例
作者:菜冻鱼
NumPy作为Python中的数值计算库,其索引、切片和迭代功能为数组操作提供了极大的便利和效率,这篇文章主要介绍了Python numpy索引与切片的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
NumPy 提供了比 Python list 强大得多的索引能力:基本索引、切片、花式索引(Fancy Indexing)、布尔索引。
基本索引与切片
一维数组
import numpy as np arr = np.array([10, 20, 30, 40, 50, 60]) # 基本索引 print(arr[0]) # 10 print(arr[-1]) # 60(倒数第一) print(arr[-2]) # 50 # 切片(返回视图,非副本!) print(arr[1:4]) # [20 30 40] print(arr[:3]) # [10 20 30](前 3 个) print(arr[3:]) # [40 50 60](从第 3 个到最后) print(arr[::2]) # [10 30 50](步长 2) print(arr[::-1]) # [60 50 40 30 20 10](反转) # 切片赋值(会修改原数组!) arr[1:4] = 99 print(arr) # [10 99 99 99 50 60]
二维数组
mat = np.arange(12).reshape(3, 4) print(mat) # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]] # 单个元素 print(mat[0, 0]) # 0 print(mat[2, -1]) # 11 # 整行 / 整列 print(mat[1]) # [4 5 6 7](第 1 行) print(mat[1, :]) # 同上 print(mat[:, 2]) # [ 2 6 10](第 2 列) # 子矩阵(切片) print(mat[0:2, 1:3]) # [[1 2] # [5 6]] # 步长切片 print(mat[::2, ::2]) # 每隔一行、每隔一列 # [[ 0 2] # [ 8 10]] # 行 + 列混合 print(mat[0, :2]) # [0 1](第 0 行前 2 列) print(mat[:2, -1]) # [3 7](前 2 行最后 1 列)
三维及以上
tensor = np.arange(24).reshape(2, 3, 4) # shape: (2, 3, 4) — 2 个矩阵,每个 3×4 print(tensor[0]) # 第一个 3×4 矩阵 print(tensor[0, 1]) # 第一个矩阵的第 1 行 → (4,) print(tensor[0, 1, 2]) # 标量 → 6 print(tensor[:, 0, :]) # 每个矩阵的第 0 行 → (2, 4) print(tensor[:, :, ::2]) # 每矩阵每隔一列 → (2, 3, 2)
...(Ellipsis)省略号
arr = np.arange(120).reshape(2, 3, 4, 5) # 等价写法 print(arr[0, :, :, :]) # 完整写法 print(arr[0, ...]) # 用 ... 代替中间的 : print(arr[..., 2]) # 最后一个维度的第 2 索引 → (2, 3, 4) print(arr[0, ..., :3]) # 第一个块,最后维取前 3 → (3, 4, 3)
花式索引(Fancy Indexing)
用整数数组来索引,返回副本(非视图)。
一维花式索引
arr = np.array([10, 20, 30, 40, 50]) # 用列表指定索引 print(arr[[0, 2, 4]]) # [10 30 50] # 可以用任意整数数组 indices = np.array([4, 1, 1, 3]) print(arr[indices]) # [50 20 20 40] # 可以任意顺序、重复 print(arr[[4, 4, 4, 0, 0]]) # [50 50 50 10 10]
二维花式索引
mat = np.arange(12).reshape(3, 4) # 指定行索引 print(mat[[0, 2]]) # 第 0 行和第 2 行 # [[ 0 1 2 3] # [ 8 9 10 11]] # 指定行 + 列索引 print(mat[[0, 2, 1], [0, 3, 1]]) # 取 (0,0), (2,3), (1,1) → [0 11 5] # ix_: 取行和列的笛卡尔积(子矩阵) print(mat[np.ix_([0, 2], [1, 3])]) # [[ 1 3] # [ 9 11]] # ix_ 等价于 mat[[0,2]][:, [1,3]]
花式索引 vs 切片
mat = np.arange(12).reshape(3, 4) # 切片返回视图 view = mat[:2, :2] view[0, 0] = 99 print(mat[0, 0]) # 99 ← 原数组被修改了! # 花式索引返回副本 copy = mat[[0, 1]][:, [0, 1]] copy[0, 0] = 999 print(mat[0, 0]) # 99 ← 原数组未修改
布尔索引
arr = np.array([15, 3, 8, 22, 1, 9, 13]) # 条件直接筛选 print(arr[arr > 10]) # [15 22 13] # 多条件(用 & | ~,必须加括号!) print(arr[(arr > 5) & (arr < 20)]) # [15 8 9 13] print(arr[(arr < 5) | (arr > 20)]) # [3 22 1] print(arr[~(arr > 10)]) # [3 8 1 9] # ⚠️ 常见错误:用 and/or 或不加括号 # arr[arr > 5 and arr < 20] ← 报错! # arr[arr > 5 & arr < 20] ← 结果错误(& 优先级高)! # arr[(arr > 5) & (arr < 20)] ← 正确!
二维布尔索引
mat = np.arange(12).reshape(3, 4) # 按条件筛选行 print(mat[mat[:, 0] > 3]) # 第 0 列 >3 的行 # [[ 4 5 6 7] # [ 8 9 10 11]] # 整体条件 mask = mat > 5 print(mat[mask]) # [6 7 8 9 10 11](返回一维数组)
布尔掩码赋值
arr = np.array([15, 3, 8, 22, 1, 9, 13]) arr[arr > 10] = 0 # 所有 >10 的变 0 print(arr) # [0 3 8 0 1 9 0] arr[arr < 5] = -1 # 所有 <5 的变 -1 print(arr) # [-1 -1 8 0 -1 9 -1]
np.where()— 条件索引三剑客
条件替换(三元运算)
arr = np.array([15, 3, 8, 22, 1, 9, 13]) # where(条件, True时的值, False时的值) result = np.where(arr > 10, 1, 0) print(result) # [1 0 0 1 0 0 1] result = np.where(arr > 10, arr, -arr) print(result) # [ 1 -3 -8 1 -1 -9 1]
条件查找(返回索引)
arr = np.array([15, 3, 8, 22, 1, 9, 13]) # 找到满足条件的索引 indices = np.where(arr > 10) print(indices) # (array([0, 3, 6]),) ← 返回元组! print(indices[0]) # [0 3 6](一维时) print(arr[indices]) # [15 22 13] # 二维 mat = np.arange(12).reshape(3, 4) rows, cols = np.where(mat > 5) print(rows) # [1 1 2 2 2 2] — 行索引 print(cols) # [2 3 0 1 2 3] — 列索引 print(mat[rows, cols]) # [6 7 8 9 10 11] — 值
多条件组合
# np.where 也可以处理多条件 arr = np.arange(10) result = np.where((arr > 3) & (arr < 8), arr * 10, arr) print(result) # [0 1 2 3 40 50 60 70 8 9]
np.argwhere()— 获取非零/True 索引
arr = np.array([0, 5, 0, 3, 0, 8, 0]) print(np.argwhere(arr > 0)) # [[1] # [3] # [5]] # 和 where 的区别:argwhere 返回 (N, ndim) 数组,where 返回元组
np.take()/np.put()— 按索引取值/设值
arr = np.array([10, 20, 30, 40, 50]) # take: 按索引取值 print(arr.take([0, 2, 4])) # [10 30 50] print(np.take(arr, [4, 3, 3])) # [50 40 40] # 二维按轴取 mat = np.arange(12).reshape(3, 4) print(np.take(mat, [0, 2], axis=0)) # 取第 0、2 行 print(np.take(mat, [0, 2], axis=1)) # 取第 0、2 列 # put: 按索引设值(原地修改) arr = np.array([10, 20, 30, 40, 50]) np.put(arr, [0, 2], [99, 88]) print(arr) # [99 20 88 40 50]
np.select()/np.clip()— 多条件/裁剪
# select: 多条件多选择 arr = np.array([15, 3, 8, 22, 1, 9, 13]) conditions = [arr < 5, arr > 15, True] # True = 兜底 choices = [-1, 1, 0] result = np.select(conditions, choices) print(result) # [0 -1 0 1 -1 0 0] # clip: 限制在范围内 print(np.clip(arr, 5, 15)) # [15 5 8 15 5 9 13] print(arr.clip(5, 15)) # 同上(方法形式)
多维索引技巧
按行列号取值
mat = np.arange(12).reshape(3, 4) # 提取对角线 print(np.diag(mat)) # [0 5 10] print(np.diag(mat, k=1)) # [1 6 11](上对角线) # 提取上三角 / 下三角 print(np.triu(mat)) # 上三角(含对角线) print(np.tril(mat, k=-1)) # 下三角(不含对角线) # 索引数组组合 row_indices = np.array([0, 1, 2]) col_indices = np.array([3, 2, 1]) print(mat[row_indices, col_indices]) # [3 6 9] — 取 (0,3),(1,2),(2,1)
按轴索引(take_along_axis)
mat = np.arange(12).reshape(3, 4) # 取每行最大值的索引对应的列 col_idx = mat.argmax(axis=1) # [3 3 3] result = np.take_along_axis(mat, col_idx[:, None], axis=1) print(result) # [[3] [7] [11]]
速查表
| 需求 | 代码 |
|---|---|
| 单个元素 | arr[0, 1] / arr[-1] |
| 整行/列 | arr[1, :] / arr[:, 2] |
| 子矩阵 | arr[0:2, 1:3] |
| 步长切片 | arr[::2, ::3] |
| 反转 | arr[::-1] |
| 省略号 | arr[0, ..., :3] |
| 花式行索引 | arr[[0, 2, 4]] |
| 笛卡尔积索引 | arr[np.ix_([0,2], [1,3])] |
| 布尔筛选 | arr[arr > 10] |
| 多条件 | arr[(a>3) & (a<10)] |
| 条件替换 | np.where(arr > 0, 1, -1) |
| 条件查找 | np.where(arr > 0) |
| 列表取值 | np.take(arr, [0, 2]) |
| 多条件选择 | np.select(conds, choices) |
| 裁剪 | np.clip(arr, lo, hi) |
[[numpy-总览|← 返回总览]]
总结
到此这篇关于Python numpy索引与切片的文章就介绍到这了,更多相关Python numpy索引与切片内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
