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 环境与核心对象关系 安装与依赖 conda / pip + NumPy BLAS / LAPACK show_config + 分解验证 核心对象 ndarray / sparse ndarray(稠密) 创建:array / zeros / arange 属性:shape、dtype、ndim strides、C_CONTIGUOUS 适用:中小规模、通用运算 示例:(3,4) float64 sparse(稀疏) 格式:COO 构造 → CSR/CSC 计算 属性:nnz、shape 转换:toarray() 核对 适用:大规模、零元占多数 示例:nnz=5, shape=(3,3) scipy.constants:物理常数与单位换算,独立于矩阵对象,供建模时直接引用

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'] 查看数值、单位与不确定度三元组。

环境自检建议固化为一段脚本:打印 SciPy/NumPy 版本、调用 show_config()、跑一次 Cholesky 并检查重构误差、创建一个小型 CSR 矩阵做一次矩阵向量乘。四项全部通过,再开始正式的科学计算任务。