NumPy 索引与切片
本章目标
- 掌握一维与二维数组的基础整数索引
- 掌握切片语法
[start:stop:step]及其在多维数组上的组合用法 - 熟练使用布尔索引完成条件过滤
- 掌握花式索引(整数数组索引)的批量取值及行列配对语义
- 掌握
np.where的"取索引 / 三元替换"两种模式
重点方法与概念速览
| 名称 | 类型 | 作用 |
|---|---|---|
arr[i]、arr[i, j] | 语法 | 基础整数索引,支持负索引 |
arr[start:stop:step] | 语法 | 切片索引,支持负步长 |
arr[row_slice, col_slice] | 语法 | 多维切片:逗号分隔各轴 |
arr[mask] | 语法 | 布尔索引:保留 True 位置元素 |
arr[[i1, i2, ...]] | 语法 | 花式索引:整数数组批量取值 |
np.where(...) | 函数 | 条件取索引或三元条件替换 |
1. 基本索引
作用
按整数位置从数组中取出单个元素。一维用单下标,二维用逗号分隔各维度下标。负数从末尾倒数(-1 为最后一个元素)。
语法
python
arr[i] # 一维
arr[i, j] # 二维
arr[i, j, k] # 三维
arr[-1] # 最后一个示例代码
python
import numpy as np
arr1d = np.array([10, 20, 30, 40, 50])
print(f"arr_1d[0] = {arr1d[0]}")
print(f"arr_1d[-1] = {arr1d[-1]}")
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(f"arr_2d[0, 0] = {arr2d[0, 0]}")
print(f"arr_2d[1, 2] = {arr2d[1, 2]}")
print(f"arr_2d[-1, -1] = {arr2d[-1, -1]}")输出
text
arr_1d[0] = 10
arr_1d[-1] = 50
arr_2d[0, 0] = 1
arr_2d[1, 2] = 6
arr_2d[-1, -1] = 9理解重点
- 推荐
arr[i, j]而非arr[i][j]:前者一次性定位,后者先切行再取列,多一次视图创建 - 越界索引抛
IndexError
2. 切片索引
一维切片
作用
按 [start:stop:step] 格式取连续或间隔的子序列。stop 不包含在结果内。步长可为负数实现反向遍历。
语法
python
arr[start:stop:step]参数
| 参数名 | 类型 | 说明 | 示例取值 |
|---|---|---|---|
start | int 或省略 | 起始位置(包含),省略时默认为 0(正步长)或末尾(负步长) | 2 |
stop | int 或省略 | 终止位置(不包含),省略时默认为末尾(正步长)或 0(负步长) | 7 |
step | int | 步长,默认为 1,可为负数表示反向 | 2、-1 |
示例代码
python
import numpy as np
arr = np.arange(10)
print(f"arr = {arr}")
print(f"arr[2:7] = {arr[2:7]}")
print(f"arr[:5] = {arr[:5]}")
print(f"arr[5:] = {arr[5:]}")
print(f"arr[::2] = {arr[::2]}")
print(f"arr[1::2] = {arr[1::2]}")
print(f"arr[::-1] = {arr[::-1]}")
print(f"arr[::-2] = {arr[::-2]}")输出
text
arr = [0 1 2 3 4 5 6 7 8 9]
arr[2:7] = [2 3 4 5 6]
arr[:5] = [0 1 2 3 4]
arr[5:] = [5 6 7 8 9]
arr[::2] = [0 2 4 6 8]
arr[1::2] = [1 3 5 7 9]
arr[::-1] = [9 8 7 6 5 4 3 2 1 0]
arr[::-2] = [9 7 5 3 1]二维切片
作用
用逗号分隔各轴的切片规则,每个轴独立遵循 [start:stop:step]。可同时控制行和列的范围。
示例代码
python
import numpy as np
arr = np.arange(20).reshape(4, 5)
print(f"原 4x5 数组:\n{arr}")
print(f"\n前 2 行 arr[:2, :]:\n{arr[:2, :]}")
print(f"\n第 2~4 列 arr[:, 1:4]:\n{arr[:, 1:4]}")
print(f"\n子矩阵 arr[1:3, 1:3]:\n{arr[1:3, 1:3]}")
print(f"\n隔行隔列 arr[::2, ::2]:\n{arr[::2, ::2]}")输出
text
原 4x5 数组:
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]
前 2 行 arr[:2, :]:
[[0 1 2 3 4]
[5 6 7 8 9]]
第 2~4 列 arr[:, 1:4]:
[[ 1 2 3]
[ 6 7 8]
[11 12 13]
[16 17 18]]
子矩阵 arr[1:3, 1:3]:
[[ 6 7]
[11 12]]
隔行隔列 arr[::2, ::2]:
[[ 0 2 4]
[10 12 14]]理解重点
- 切片返回的是视图,修改切片会影响原数组——需要独立数据用
.copy() stop不包含在结果内;反向切片时start应大于stop(如arr[5:1:-1])
3. 布尔索引
作用
用同形状的布尔数组作为索引,保留 True 位置的元素,返回新数组(拷贝)。是 NumPy 条件过滤的最高效方式。
多条件组合
| 运算符 | 含义 | 示例 |
|---|---|---|
& | 逻辑与 | (arr >= 3) & (arr <= 7) |
| | 逻辑或 | (arr < 3) | (arr > 8) |
~ | 逻辑非 | ~(arr > 5) |
不能使用 Python 的 and/or/not。每个条件必须加括号防止运算符优先级问题。
示例代码
python
import numpy as np
arr = np.arange(1, 11)
print(f"原数组: {arr}")
print(f"arr > 5: {arr[arr > 5]}")
print(f"arr % 2 == 0: {arr[arr % 2 == 0]}")
print(f"(arr >= 3) & (arr <= 7): {arr[(arr >= 3) & (arr <= 7)]}")
print(f"(arr < 3) | (arr > 8): {arr[(arr < 3) | (arr > 8)]}")
print(f"~(arr > 5): {arr[~(arr > 5)]}")输出
text
原数组: [ 1 2 3 4 5 6 7 8 9 10]
arr > 5: [ 6 7 8 9 10]
arr % 2 == 0: [ 2 4 6 8 10]
(arr >= 3) & (arr <= 7): [3 4 5 6 7]
(arr < 3) | (arr > 8): [ 1 2 9 10]
~(arr > 5): [1 2 3 4 5]理解重点
- 布尔索引返回拷贝,修改不影响原数组——与切片(视图)相反
&/|的优先级高于比较运算符,不加括号会导致arr >= 3 & arr <= 7被解析为arr >= (3 & arr) <= 7,报错
4. 花式索引
作用
用整数列表或数组作为索引,按指定位置批量取值。传入两个索引数组时按"行列配对"取元素,而非笛卡儿积。
语法
python
arr[[i1, i2, i3, ...]] # 一维批量取
arr2d[[r1, r2, ...]] # 取多行
arr2d[[r1, r2, ...], [c1, c2, ...]] # 按行列对逐元素取示例代码
python
import numpy as np
arr = np.arange(10, 20)
print(f"原数组: {arr}")
print(f"arr[[0, 2, 5, 8]]: {arr[[0, 2, 5, 8]]}")
arr2d = np.arange(12).reshape(3, 4)
print(f"\n二维数组:\n{arr2d}")
print(f"\n选第 0、2 行:\n{arr2d[[0, 2]]}")
print(f"\n对角线 (0,0)(1,1)(2,2): {arr2d[[0, 1, 2], [0, 1, 2]]}")输出
text
原数组: [10 11 12 13 14 15 16 17 18 19]
arr[[0, 2, 5, 8]]: [10 12 15 18]
二维数组:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
选第 0、2 行:
[[ 0 1 2 3]
[ 8 9 10 11]]
对角线 (0,0)(1,1)(2,2): [ 0 5 10]理解重点
- 花式索引返回拷贝,不是视图——与布尔索引一致
- 传入两个索引数组时,结果是"行列逐对组合"而非笛卡儿积——需要笛卡儿积用
np.ix_
5. 条件函数
np.where
作用
有两种使用模式:
np.where(condition)——返回满足条件的元素索引(元组)np.where(condition, x, y)——条件三元替换,取 , 取
重点方法
python
np.where(condition, [x, y])参数
| 参数名 | 类型 | 说明 | 示例取值 |
|---|---|---|---|
condition | array_like | 布尔数组或可广播到目标形状的条件表达式 | arr > 0 |
x | scalar 或 array_like | 条件为 True 时取的值,与 y 必须同时提供 | arr、1 |
y | scalar 或 array_like | 条件为 False 时取的值 | 0、-1 |
示例代码
python
import numpy as np
arr = np.array([1, -2, 3, -4, 5, -6])
# 模式 1:取索引
idx = np.where(arr > 0)
print(f"正数的索引: {idx[0]}")
print(f"正数的值: {arr[idx]}")
# 模式 2:条件替换
print(f"负数替换为 0: {np.where(arr > 0, arr, 0)}")
print(f"正数标 1 其他 -1: {np.where(arr > 0, 1, -1)}")输出
text
正数的索引: [0 2 4]
正数的值: [1 3 5]
负数替换为 0: [1 0 3 0 5 0]
正数标 1 其他 -1: [ 1 -1 1 -1 1 -1]理解重点
np.where(cond)返回元组,一维场景取[0]得到索引数组np.where(cond, x, y)中x、y可以是标量或数组,自动广播到condition的形状
常见坑
- 切片返回视图,花式索引和布尔索引返回拷贝——修改行为不同
- 二维索引推荐
arr[i, j]而非arr[i][j]——后者多一次视图创建 - 布尔条件组合必须加括号且用
&/|:(arr >= 3) & (arr <= 7)而非arr >= 3 & arr <= 7 np.where(cond, x, y)中x/y必须同时提供;只传cond是取索引模式- 传两个索引数组取二维元素时是"行列配对"而非笛卡儿积——需要子矩阵用
np.ix_
小结
- 索引决定了对数组的表达力,是一切后续操作的基础
- 布尔索引和
np.where是数据清洗、特征工程的高频工具 - 切片 = 视图,花式/布尔索引 = 拷贝——这个区别影响内存、性能和是否修改原数组