跳转到内容

SciPy — NumPy 之上的科学计算工具箱

待复核

SciPy 是 Python 科学计算的标准扩展库——给 NumPy 的多维数组配上一整套工程算法:统计检验、最优化、数值积分、信号处理、稀疏矩阵、空间数据结构……都装在一个 scipy 包里。日常类比:NumPy 像一张白纸 + 一把直尺,能量长度算面积;SciPy 是配套的整套工具箱——圆规、三角板、量角器、计算器,每件都对应一个工程领域。

你写:

from scipy.optimize import minimize
result = minimize(lambda x: (x[0] - 3)**2 + (x[1] + 1)**2, x0=[0, 0])
print(result.x) # 接近 [3, -1]

只调一个函数,背后是几十年沉淀的 Fortran 数值代码(MINPACK / L-BFGS-B)。SciPy 把这些”工业级硬核算法”包装成 Python 接口,让你不用懂 Fortran 也能用上。

不理解 SciPy,下面这些事都没法解释:

  • 为什么 scikit-learn / statsmodels / scikit-image / PyMC 都默认装好就能用——它们底层全靠 scipy.sparse / scipy.optimize / scipy.linalg
  • 为什么”用 Python 做科研”敢说和 MATLAB 抗衡:因为 SciPy 包装了 LAPACK / BLAS / ARPACK 这些 MATLAB 也在用的同一批 Fortran 库
  • 为什么处理”100 万维线性方程”要用 scipy.sparse 而不是 numpy——稀疏存储 + 专用解法器才能让内存和时间都压下来
  • 为什么 1990 年代的 Fortran 代码到 2026 年还在跑——SciPy 是最大的”古老数值库现代化封装层”

SciPy 的设计可以拆成 三层

  1. NumPy 数组当通用语言:所有子模块的输入输出都是 numpy.ndarray(或 scipy.sparse 稀疏矩阵)。类比:USB 接口——任何外设只要支持就能插。这让 SciPy / scikit-learn / pandas 能无缝串起来。

  2. Python 做胶水,Fortran/C 做计算:Python 层做参数校验、数据转换、错误信息;真正的数值循环在 LAPACK(线代)/ QUADPACK(积分)/ MINPACK(最小二乘)/ ARPACK(稀疏特征值)里跑。类比:餐厅前台用中文点单,后厨用各国母语做菜。

  3. 子模块自治scipy.stats / scipy.optimize / scipy.signal / scipy.sparse / scipy.linalg / scipy.spatial 各管一摊,接口风格也各自独立。类比:同一栋楼的不同诊室——挂号规则可能不一样,但都属一家医院。

import numpy as np
from scipy.optimize import curve_fit
# 模拟指数衰减数据:y = a * exp(-b * x) + 噪声
x = np.linspace(0, 4, 50)
y_true = 2.5 * np.exp(-1.3 * x)
y_obs = y_true + 0.2 * np.random.randn(len(x))
def model(x, a, b):
return a * np.exp(-b * x)
popt, pcov = curve_fit(model, x, y_obs, p0=[1, 1])
print(popt) # 接近 [2.5, 1.3]
print(np.sqrt(np.diag(pcov))) # 每个参数的标准误差

逐部分解释

  • 输入:造出带噪声的指数衰减曲线,并写好待拟合公式 model
  • 调用:curve_fit 从初值 p0 出发,找最贴近数据的 a, b
  • 读输出:popt 是最优参数;pcov 协方差对角线开方就是参数不确定度(误差棒)。
from scipy.sparse import diags
from scipy.sparse.linalg import spsolve
n = 1_000_000
# 三对角矩阵:主对角 2,上下对角 -1(一维拉普拉斯算子)
A = diags([-1, 2, -1], [-1, 0, 1], shape=(n, n), format='csr')
b = np.ones(n)
x = spsolve(A, b)

逐部分解释

  • 输入:用 diags 只存三条对角线上的非零数,得到 CSR 稀疏矩阵 A
  • 调用:spsolve 对稀疏结构做分解求解,不必把整张表摊开。
  • 读输出:若用稠密 numpy 存,光内存约 8 TB(10⁶×10⁶×8 byte);稀疏路径才是有限元 / 电路仿真的常态。
from scipy import stats
group_a = [23, 25, 21, 29, 27, 24]
group_b = [30, 28, 35, 32, 31, 33]
# 假设正态:t 检验
t_stat, p_t = stats.ttest_ind(group_a, group_b)
# 不假设分布:Mann-Whitney U 检验(只比谁更大,不假设钟形曲线)
u_stat, p_u = stats.mannwhitneyu(group_a, group_b)
print(f"t-test p={p_t:.4f}, U-test p={p_u:.4f}")

逐部分解释

  • 输入:两组小数列表;样本小、分布未必正态。
  • 调用:先跑 ttest_ind(吃正态假设),再跑 mannwhitneyu(只比排序,更稳)。
  • 读输出:看 p 值;前提不成立时更信 U 检验。scipy.stats 是统计”急救包”。
  1. scipy.linalgnumpy.linalg:两者多数底层都碰 LAPACK,但 scipy.linalg 封装更全(QR / Schur / 完整 Cholesky 等),同名函数(如 solve / eig)也常更快——做密集线代优先用 scipy.linalg

  2. 稀疏格式选错性能崩盘LIL / DOK 适合”边构造边改”,CSR / CSC 适合矩阵乘法和解方程。构建完没 .tocsr() 就直接乘,每次都会重建索引,慢上百倍。

  3. optimize.minimize 默认方法不一定收敛:有梯度选 BFGS / L-BFGS-B;无梯度选 Nelder-Mead / Powell;带约束用 SLSQP / trust-constr。选错可能给你一个”看着正常但是错的”局部极值,且不报错。

  4. 尾部概率千万别用 1 - cdf:当 cdf(x) 接近 1 时,1 - cdf(x) 浮点截断成 0;要用 sf(x)(survival function),它在尾部保持精度。stats.norm.sf(10) ≈ 7.6e-24,而 1 - stats.norm.cdf(10) 可能直接给 0。

适用

  • 数值科研、工程仿真、信号 / 图像处理、统计建模、稀疏线代
  • 需要”调一行代码就能用工业级算法”的场景(拟合、解方程、做检验)
  • 和 NumPy / pandas / scikit-learn 一起搭数据科学流水线

不适用

  • GPU 加速 / 自动求导 → 用 PyTorch / JAX
  • 大规模分布式计算 → 用 Dask / Ray
  • 符号计算(解方程的解析解)→ 用 SymPy
  • 真·实时控制 → SciPy 是离线计算工具,不保证毫秒级延迟
  • 2001 年:Travis Oliphant、Eric Jones、Pearu Peterson 把各自写的数值模块合并,发布 SciPy 0.1,已能调 LAPACK 解线代。
  • 2005–2006 年:Oliphant 把 Numeric 与 Numarray 的长处合成 NumPy;SciPy 稳定成「NumPy 当数组层 + SciPy 当算法层」。
  • 2017 年:SciPy 1.0 正式版发布,距首发约 16 年,宣告核心接口成熟。
  • 2020 年:Virtanen 等在 Nature Methods 发表 SciPy 1.0 综述,把它写成科学计算基础设施。
  • 2020 年起:每年稳定大版本,逐步把 Fortran 迁到 C/C++、加现代构建,迈向 Python 3-only。
  1. Python 不是科学计算的发明者,是封装者——SciPy 让 1970-1990 年代的 Fortran 巨人们继续在 2026 年发光
  2. API 一致性 ≠ 实现一致性:同一个 solvenumpy.linalgscipy.linalg 里走不同路径,性能差几倍
  3. 稀疏 / 稠密分家是数值计算的核心抽象:选对存储格式比换算法影响更大
  4. 生态先于库:SciPy 的真正威力不是它自己,是 scikit-learn / statsmodels / scikit-image 都用它当地基
  • 官方文档:SciPy User Guide(每个子模块都有零基础教程)
  • 视频:SciPy 2024 Tutorials(每年大会全程录像,免费)
  • 书:Robert Johansson《Numerical Python》第 2 版(手把手讲 NumPy + SciPy + Matplotlib + Pandas)
  • 论文:Virtanen et al. “SciPy 1.0: fundamental algorithms for scientific computing in Python”, Nature Methods 2020(官方综述)
  • numpy —— SciPy 的地基,多维数组的事实标准
  • pandas —— 上层表格分析常和 SciPy 统计模块串用
  • numpy —— SciPy 把所有输入输出都当 numpy.ndarray,是物理上的依赖关系
  • pandas —— DataFrame 的 .values 直接喂给 SciPy;统计建模常 pandas + scipy.stats
  • scikit-learn —— 经典 ML 大量依赖 scipy.sparse / scipy.optimize / scipy.linalg
  • polars —— 新一代列存表格库,和 SciPy 的桥还在生态早期,但思想类似(zero-copy)
  • dask —— 内存装不下时,用 Dask 数组/调度把 SciPy 式计算摊到集群
  • dask —— Dask — 让 pandas / NumPy 直接跑在比内存大的数据上
  • dlib —— dlib — C++ 机器学习 / CV 工具箱
  • pyarrow —— PyArrow — 让所有数据系统共用一块内存
  • scikit-learn —— scikit-learn — 经典 ML 库
  • sox —— SoX — 命令行音频处理瑞士军刀