Skip to content

NumPy 索引与切片

本章目标

  1. 掌握一维与二维数组的基础整数索引
  2. 掌握切片语法 [start:stop:step] 及其在多维数组上的组合用法
  3. 熟练使用布尔索引完成条件过滤
  4. 掌握花式索引(整数数组索引)的批量取值及行列配对语义
  5. 掌握 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]

参数

参数名类型说明示例取值
startint 或省略起始位置(包含),省略时默认为 0(正步长)或末尾(负步长)2
stopint 或省略终止位置(不包含),省略时默认为末尾(正步长)或 0(负步长)7
stepint步长,默认为 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

作用

有两种使用模式:

  1. np.where(condition) ——返回满足条件的元素索引(元组)
  2. np.where(condition, x, y) ——条件三元替换,TruexFalsey

重点方法

python
np.where(condition, [x, y])

参数

参数名类型说明示例取值
conditionarray_like布尔数组或可广播到目标形状的条件表达式arr > 0
xscalararray_like条件为 True 时取的值,与 y 必须同时提供arr1
yscalararray_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)xy 可以是标量或数组,自动广播到 condition 的形状

常见坑

  1. 切片返回视图,花式索引和布尔索引返回拷贝——修改行为不同
  2. 二维索引推荐 arr[i, j] 而非 arr[i][j]——后者多一次视图创建
  3. 布尔条件组合必须加括号且用 &/|(arr >= 3) & (arr <= 7) 而非 arr >= 3 & arr <= 7
  4. np.where(cond, x, y)x/y 必须同时提供;只传 cond 是取索引模式
  5. 传两个索引数组取二维元素时是"行列配对"而非笛卡儿积——需要子矩阵用 np.ix_

小结

  • 索引决定了对数组的表达力,是一切后续操作的基础
  • 布尔索引和 np.where 是数据清洗、特征工程的高频工具
  • 切片 = 视图花式/布尔索引 = 拷贝——这个区别影响内存、性能和是否修改原数组