← 返回学习中心ARC LAB / LEARNING NOTES

Python 专区

Python NumPy

数组形状、索引、广播、视图与统计,用实际数组图掌握数值计算。

展开本篇目录

一、为什么学习 NumPy?

NumPy 用 ndarray 存储和计算同类数值数据,是 pandas、图像处理和许多科学计算工具的基础。学会它不仅是为了“少写循环”,更是为了看懂数组的形状、类型和运算含义。

先修:Python 列表、循环与函数。学习路线:创建数组 → 索引 → shape 与 axis → 广播 → 统计 → 复制和存储。先用小数组手算,再对照程序输出。

python -m pip install numpy matplotlib

NumPy 自身不负责通用绘图,本篇配套 Matplotlib 用于展示数组。

二、列表与数组的关键区别

import numpy as np
print([1, 2] * 2) # [1, 2, 1, 2]
print(np.array([1, 2]) * 2) # [2 4]

列表乘法重复内容,数组乘法逐元素计算。数组通常使用统一 dtype;不要把混杂的文本和数字强行塞入同一个数值数组。

三、创建数组与检查属性

a = np.arange(12, dtype=np.float64).reshape(3, 4)
print(a)
print(a.shape, a.ndim, a.size, a.dtype)
[[ 0.  1.  2.  3.]
[ 4. 5. 6. 7.]
[ 8. 9. 10. 11.]]
(3, 4) 2 12 float64
接口 用途 示例
array 从已有数据建立数组 np.array([1,2,3])
zeros/ones 按形状创建 np.zeros((2,3))
arange 等步长序列 np.arange(0,10,2)
linspace 指定数量的等间隔点 np.linspace(0,1,5)
reshape 重新组织形状 a.reshape(4,3)
astype 转换 dtype a.astype(np.float32)

浮点步长的 arange 可能有舍入与端点问题;需要明确点数时使用 linspace。reshape 前后元素总数必须一致,不能自动补值。

四、索引、切片与布尔条件

a = np.arange(12).reshape(3,4)
print(a[1, 2]) # 6
print(a[:, 1:3]) # 所有行,第 1、2 列
print(a[a >= 8]) # [8 9 10 11]
mask = (a >= 4) & (a < 8)
print(a[mask]) # [4 5 6 7]

切片是左闭右开。多元素条件使用 &、| 并给每个比较加括号;不能用 Python 的 and 将两个数组当单一真假值。

五、axis:沿哪一个维度汇总?

3×4 数组沿 axis=0 汇总得到四列统计,沿 axis=1 汇总得到三行统计

print(a.sum(axis=0))   # [12 15 18 21]:压缩行轴,保留各列
print(a.sum(axis=1)) # [ 6 22 38]:压缩列轴,保留各行

记法:axis 指定被归约掉的维度。不要只背“0 是行、1 是列”,然后把输出方向记反。keepdims=True 会保留长度为 1 的维度,方便后续广播。

六、广播:形状兼容才能计算

实际计算的数组、三行均值,以及减去各行均值后的结果

a = np.arange(12, dtype=float).reshape(3,4)
row_mean = a.mean(axis=1, keepdims=True) # shape (3,1)
centered = a - row_mean # shape (3,4)
print(row_mean.ravel()) # [1.5 5.5 9.5]
print(centered.mean(axis=1)) # [0. 0. 0.]

从最右边的维度开始对齐:两个维度相同,或其中一个为 1,才兼容。(3,4) 与 (3,1) 兼容,而 (3,4) 与 (3,) 不兼容。去掉 keepdims 后,应使用 row_mean[:,None] 恢复列形状。

广播通常不需要实际复制那一列均值,但运算输出仍会占内存。构造巨大的两两差值矩阵时,需要先估算结果尺寸。

七、逐元素乘法与矩阵乘法

x = np.array([[1,2],[3,4]])
y = np.array([[2,0],[0,2]])
print(x * y) # 逐元素:[[2,0],[0,8]]
print(x @ y) # 矩阵乘:[[2,4],[6,8]]

矩阵乘法要求内侧维度一致。求解 Ax=b 时通常使用 np.linalg.solve(A,b),而不是先计算显式逆矩阵;奇异矩阵、病态数据和浮点误差仍需检查。

八、dtype、溢出、缺失值与浮点误差

  • 固定宽度整数可能溢出;计算前检查 dtype,不能假设数组整数与 Python 任意精度整数相同。
  • 图像的 uint8 运算尤其要注意,必要时先转浮点,再截断回合法范围。
  • NaN 需要 np.isnan 或 np.isfinite 检查,不用 value == np.nan。
  • np.mean 会传播 NaN;np.nanmean 忽略 NaN,但全是 NaN 时依然没有有效均值。
  • 浮点结果比较使用容差,如 np.allclose、np.testing.assert_allclose,不要普遍要求精确相等。

九、视图与副本:修改为什么会影响原数组?

a = np.arange(6).reshape(2,3)
view = a[:,1:]
view[0,0] = 99
assert a[0,1] == 99
independent = a[:,1:].copy()
independent[0,0] = -1
assert a[0,1] == 99

基本切片通常得到视图;高级索引、布尔索引通常得到副本。reshape 是否共享内存取决于布局,不能一概当作复制。需要独立数据时明确 .copy(),需要检查可用 np.shares_memory。

十、随机数与读写

rng = np.random.default_rng(42)
noise = rng.normal(0, 1, size=(3,4))
np.save("noise.npy", noise)
restored = np.load("noise.npy")
np.testing.assert_allclose(restored, noise)

固定种子便于同一环境复现实验,但不应声称所有 NumPy 版本的所有算法输出都永久一致。保存普通数值数组不需要 pickle;不要为读取来源不明的对象数组随意开启 allow_pickle=True。

十一、完整实验与结果

下载 numpy_demo.py:

python numpy_demo.py --output results

脚本检查形状、广播后行均值为 0、视图与副本的行为,并保存配图和 centered.npy。预期输出三行均值 [1.5,5.5,9.5],中心化均值均为 0。

十二、练习与排错

  1. 把数组改成 4×3,预测 axis=0/1 输出形状,再运行核对。
  2. 按列中心化。参考:a - a.mean(axis=0, keepdims=True)。
  3. 用布尔掩码统计 60~100 的有效成绩,保留合法零分的概念不要混淆。
  4. 故意让 (3,4) 减 (3,),解释广播异常,而不是盲目 reshape。
  5. 小项目:对多通道传感器数据按列求均值、标准差,明确处理全空列和零标准差。

常见问题:结果形状不对先打印 shape;值异常先看 dtype;修改相互影响先检查共享内存;性能问题先避免重复复制,再决定是否矢量化。

十三、学习资料

← 继续探索学习路径反馈问题 ↗