2. 环境搭建与SciPy核心对象
SciPy 本身是一个建立在 NumPy 之上的科学计算库,它的绝大多数函数都直接接收或返回 ndarray,而线性代数、稀疏矩阵、插值、优化等模块又依赖底层编译好的 BLAS/LAPACK 实现。因此,环境搭建不只是“装一个包”,而是要确认三件事:SciPy 与 NumPy 版本匹配、底层线性代数后端可用、核心对象能正常创建并参与运算。本节围绕这条主线展开,并补充 scipy.constants 的常用方式。
安装与依赖关系
推荐使用 conda 或 pip 在独立虚拟环境中安装,避免与系统 Python 冲突。SciPy 的硬依赖是 NumPy,二者版本需要兼容,例如 SciPy 1.11 要求 NumPy ≥ 1.21.6。安装时让包管理器自动解析依赖即可:
# 方式一:conda(推荐,自带优化过的 BLAS)
conda create -n scipy-env python=3.11
conda activate scipy-env
conda install scipy numpy
# 方式二:pip
python -m venv scipy-env
source scipy-env/bin/activate # Windows 用 scipy-env\Scripts\activate
pip install scipy numpy
安装完成后先做版本核对,确认 SciPy、NumPy 与 Python 三者版本互相兼容:
import sys, numpy, scipy
print(sys.version)
print("numpy", numpy.__version__)
print("scipy", scipy.__version__)
如果输出中 SciPy 版本正常打印且无 ImportError,说明包本身可用;但“能导入”不等于“线性代数后端正常”,下一步必须验证 BLAS/LAPACK。
验证 BLAS/LAPACK 后端
BLAS 负责向量与矩阵的基础运算,LAPACK 负责分解、求解特征值等高层线性代数。SciPy 通过 scipy.linalg 调用它们。可用 numpy.show_config() 查看 NumPy 链接的后端,用 scipy.show_config() 查看 SciPy 的构建信息:
import numpy as np
import scipy
np.show_config()
scipy.show_config()
输出中若出现 openblas、mkl 或 blis 等名称,说明已链接到优化后端;若显示 blas/lapack 的通用参考实现,则性能会明显偏低。更直接的验证是跑一次真实分解,观察是否报错以及耗时量级:
import numpy as np
from scipy import linalg
import time
rng = np.random.default_rng(0)
A = rng.standard_normal((800, 800))
A = A @ A.T + 800 * np.eye(800) # 构造对称正定矩阵
t0 = time.perf_counter()
c = linalg.cholesky(A, lower=True)
t1 = time.perf_counter()
# 用分解结果回代验证:L @ L.T 应还原 A
err = np.max(np.abs(c @ c.T - A))
print(f"cholesky 耗时 {t1-t0:.4f}s, 重构误差 {err:.2e}")
判断依据有两条:重构误差应在 1e-10 量级(浮点舍入范围内),说明 LAPACK 的 Cholesky 例程工作正常;耗时在毫秒到几十毫秒量级,说明 BLAS 后端有实际加速。若误差异常大或直接抛出 LinAlgError,应优先怀疑后端链接损坏,可尝试重装 NumPy/SciPy 或改用 conda 的 MKL 版本。
ndarray 与稀疏矩阵:创建与属性
ndarray 是 SciPy 的通用数据载体,稠密矩阵直接用二维 ndarray 表示。创建方式包括 np.array、np.zeros、np.arange 以及随机生成。关键属性有 shape(形状)、dtype(元素类型)、ndim(维数)、strides(步长)和 flags(是否 C 连续)。
import numpy as np
A = np.arange(12, dtype=np.float64).reshape(3, 4)
print(A.shape, A.dtype, A.ndim) # (3, 4) float64 2
print(A.flags['C_CONTIGUOUS']) # True
当矩阵规模大而零元素占绝大多数时,应改用 scipy.sparse 中的稀疏格式。常用格式有 COO(坐标列表,适合构造)、CSR(按行压缩,适合行切片与矩阵向量乘)、CSC(按列压缩,适合列切片)。稀疏矩阵的核心属性是 nnz(非零元个数)和 shape,并可通过 toarray() 转回稠密形式核对。
from scipy import sparse
import numpy as np
# 用 COO 三元组构造:行、列、值
rows = np.array([0, 0, 1, 2, 2])
cols = np.array([0, 2, 1, 0, 2])
vals = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
coo = sparse.coo_matrix((vals, (rows, cols)), shape=(3, 3))
csr = coo.tocsr()
print(coo.nnz, csr.shape) # 5 (3, 3)
print(csr.toarray())
print(csr @ np.array([1.0, 1.0, 1.0])) # 稀疏矩阵向量乘
选择格式的经验是:构造阶段用 COO 或 lil_matrix 逐项填充,计算阶段转成 CSR/CSC。稀疏矩阵与 ndarray 的运算接口基本一致,但要注意稀疏矩阵不支持所有 NumPy 广播语义,混合运算时优先用 @ 和 scipy.sparse.linalg 中的求解器。
scipy.constants 物理常数使用
scipy.constants 提供 CODATA 推荐的物理常数、单位前缀和换算函数,避免手写数值时引入精度或量纲错误。常数以属性方式访问,例如光速 c、普朗克常数 h、玻尔兹曼常数 k、元电荷 e,单位均为国际单位制。
from scipy import constants as C
print(C.c) # 299792458.0 m/s
print(C.h) # 6.62607015e-34 J·s
print(C.k) # 1.380649e-23 J/K
print(C.e) # 1.602176634e-19 C
# 单位换算:电子伏特转焦耳
print(C.electron_volt) # 1.602176634e-19
# 波长 500 nm 光子的能量(J 与 eV)
lam = 500e-9
E = C.h * C.c / lam
print(E, E / C.electron_volt) # 约 3.97e-19 J,约 2.48 eV
常用辅助函数还有 C.convert_temperature(摄氏/华氏/开尔文互转)、C.gram、C.milli 等单位前缀常量。在建模时直接引用常数对象,比硬编码数值更利于复现和审阅;若需要某一版本的 CODATA 值,可通过 C.physical_constants['speed of light in vacuum'] 查看数值、单位与不确定度三元组。
show_config()、跑一次 Cholesky 并检查重构误差、创建一个小型 CSR 矩阵做一次矩阵向量乘。四项全部通过,再开始正式的科学计算任务。