Skip to content

索引与切片 ​

NumPy 的索引和切片是访问与操作数组元素的基础。相比 Python 列表,NumPy 支持更强大的多维索引机制,包括基础索引、切片、布尔索引和花式索引。

一、基础索引 ​

1、一维数组 ​

python
import numpy as np

a = np.array([10, 20, 30, 40, 50])

print(a[0])      # 10      — 第一个元素
print(a[-1])     # 50      — 最后一个元素
print(a[2])      # 30      — 第三个元素

2、多维数组 ​

python
b = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 9]])

print(b[0])        # [1 2 3]      — 第一行
print(b[0, 2])     # 3            — 第一行第三列
print(b[-1, -1])   # 9            — 最后一行最后一列
print(b[1][2])     # 6            — 等价于 b[1, 2](但效率较低)

优先使用 b[i, j] 而非 b[i][j]

b[i, j] 一次索引完成,而 b[i][j] 先取第 i 行再取第 j 列,会创建临时数组。两者结果相同,但前者更高效。

3、高维数组 ​

python
c = np.arange(24).reshape(2, 3, 4)  # 形状 (2, 3, 4)

print(c[0])           # 第一个 (3, 4) 子数组
print(c[0, 1])        # 第一个子数组的第二行 → shape (4,)
print(c[0, 1, 2])     # 标量值 6

二、切片(Slicing) ​

切片语法:start:stop:step,与 Python 列表一致。

1、一维切片 ​

python
a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

print(a[2:6])      # [2 3 4 5]
print(a[::2])      # [0 2 4 6 8]     — 步长为 2
print(a[::-1])     # [9 8 7 6 5 4 3 2 1 0]  — 反转
print(a[5:])       # [5 6 7 8 9]     — 从第 6 个到末尾
print(a[:3])       # [0 1 2]         — 前 3 个

2、多维切片 ​

python
b = np.arange(16).reshape(4, 4)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]
#  [12 13 14 15]]

print(b[0:2, 0:2])
# [[0 1]
#  [4 5]]               — 左上角 2×2 子矩阵

print(b[:, 1])
# [ 1  5  9 13]         — 第二列

print(b[1:3, :])
# [[ 4  5  6  7]
#  [ 8  9 10 11]]       — 中间两行

print(b[::2, ::2])
# [[ 0  2]
#  [ 8 10]]             — 隔行隔列取

3、切片是视图 ​

python
a = np.array([1, 2, 3, 4, 5])
s = a[1:4]        # 视图,共享内存
s[0] = 99
print(a)           # [ 1 99  3  4  5]  — 原数组被修改

这意味着切片赋值可以直接修改原数组:

python
a = np.array([1, 2, 3, 4, 5])
a[1:4] = [20, 30, 40]
print(a)           # [ 1 20 30 40  5]

三、布尔索引(Boolean Indexing) ​

通过布尔数组(掩码)筛选元素,返回的是副本。

1、基本用法 ​

python
a = np.array([10, 20, 30, 40, 50])

mask = a > 25
print(mask)         # [False False  True  True  True]

print(a[mask])      # [30 40 50]

# 一行写法
print(a[a > 25])    # [30 40 50]

2、多条件组合 ​

python
a = np.array([10, 20, 30, 40, 50])

# 与(&)、或(|)、非(~)
print(a[(a > 15) & (a < 45)])   # [20 30 40]
print(a[(a < 20) | (a > 45)])   # [10 50]
print(a[~(a > 30)])              # [10 20 30]

注意运算符优先级

在布尔索引中,必须使用 &、|、~(位运算符),不能用 and、or、not(Python 关键字)。同时每个条件必须加括号:(a > 15) & (a < 45)。

3、二维布尔索引 ​

python
b = np.arange(12).reshape(3, 4)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

# 筛选所有偶数
print(b[b % 2 == 0])   # [ 0  2  4  6  8 10]

# 按行条件筛选
row_mask = np.array([True, False, True])
print(b[row_mask])
# [[ 0  1  2  3]
#  [ 8  9 10 11]]

# np.where: 返回满足条件的元素索引
rows, cols = np.where(b > 5)
print(list(zip(rows, cols)))  # [(1,2), (1,3), (2,0), (2,1), (2,2), (2,3)]

4、np.where 条件赋值 ​

python
a = np.array([1, 2, 3, 4, 5])

# 三元表达式:满足条件取 x,否则取 y
result = np.where(a > 3, a, 0)
print(result)   # [0 0 0 4 5]

# 等价于
result = np.where(a > 3, a * 10, -1)
print(result)   # [-1 -1 -1 40 50]

四、花式索引(Fancy Indexing) ​

用整数数组作为索引,返回的是副本而非视图。

1、一维花式索引 ​

python
a = np.array([10, 20, 30, 40, 50])

indices = [0, 2, 4]
print(a[indices])        # [10 30 50]

# 重复索引
print(a[[0, 0, 2, 2]])  # [10 10 30 30]

# 用数组作为索引
idx = np.array([3, 1, 4])
print(a[idx])            # [40 20 50]

2、二维花式索引 ​

python
b = np.arange(12).reshape(3, 4)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

# 选取特定行
print(b[[0, 2]])
# [[ 0  1  2  3]
#  [ 8  9 10 11]]

# 选取特定行列交叉点(配对索引)
row_idx = np.array([0, 1, 2])
col_idx = np.array([1, 2, 3])
print(b[row_idx, col_idx])   # [ 1  6 11]  → (0,1), (1,2), (2,3)

3、ix_ 网格索引 ​

python
b = np.arange(12).reshape(3, 4)

# np.ix_ 创建开放网格
rows = [0, 2]
cols = [1, 3]
print(b[np.ix_(rows, cols)])
# [[ 1  3]
#  [ 9 11]]        — 取第 0、2 行与第 1、3 列的交叉子矩阵

4、花式索引与切片组合 ​

python
b = np.arange(12).reshape(3, 4)

# 切片 + 花式索引
print(b[1:, [0, 2]])
# [[ 4  6]
#  [ 8 10]]        — 后两行,第 0 和第 2 列

五、索引赋值 ​

所有索引方式都支持赋值:

python
a = np.zeros((3, 3))

# 基础索引赋值
a[0, 0] = 1

# 切片赋值
a[1, :] = [4, 5, 6]

# 布尔索引赋值
a[a > 3] = 99

# 花式索引赋值
a[[0, 2], [0, 2]] = [7, 8]

print(a)
# [[ 7.  0.  0.]
#  [99. 99. 99.]
#  [ 0.  0.  8.]]

六、省略号(...)与 np.newaxis ​

1、省略号 ... ​

在高维数组中,... 代表"所有剩余维度":

python
c = np.arange(24).reshape(2, 3, 4)

print(c[0, ...])      # 等价于 c[0, :, :]
print(c[..., 0])      # 等价于 c[:, :, 0]
print(c[0, ..., 2])   # 等价于 c[0, :, 2]

2、np.newaxis 增加维度 ​

python
a = np.array([1, 2, 3])       # shape (3,)

print(a[:, np.newaxis])        # shape (3, 1) — 列向量
# [[1]
#  [2]
#  [3]]

print(a[np.newaxis, :])        # shape (1, 3) — 行向量
# [[1 2 3]]

📖 官方文档