Cholesky分解前须验证矩阵正定性,因np.linalg.cholesky不检查而直接报错;推荐检验对称性与特征值,并修正微小负值;大规模矩阵需用scipy稀疏或原地分解;dtype选float32可提速降内存;解方程应链式调用scipy.linalg.solve_triangular。

Cholesky分解前必须确认矩阵正定性
NumPy的np.linalg.cholesky不检查输入是否正定,直接对非正定矩阵调用会抛出LinAlgError: Matrix is not positive definite。这不是bug,是设计使然——它假设你已确保前提成立。
实际中,浮点误差常让本该正定的协方差矩阵在数值上“差点意思”。推荐先做快速检验:
- 检查对称性:
np.allclose(A, A.T)(容忍浮点误差) - 检查特征值全为正:
np.all(np.linalg.eigvalsh(A) > 1e-10)(eigvalsh专用于实对称阵,比eigvals快且稳定) - 若发现微小负特征值(如-1e-15),可主动修正:
A = A + 1e-10 * np.eye(A.shape[0])
大规模矩阵下避免内存爆炸的两种策略
当矩阵尺寸超过几万×几万,np.linalg.cholesky会一次性分配L矩阵内存(约½n²个浮点数),极易OOM。此时不能只依赖单次调用。
可行路径有二:
立即学习“Python免费学习笔记(深入)”;
- 用
scipy.linalg.cholesky配合overwrite_a=True参数,允许原地分解(节省½内存),但要求输入数组是C连续且可写 - 对分块矩阵(如稀疏或结构化协方差),改用
scipy.sparse.linalg.splu或专门库(如cholmod绑定),np.linalg.cholesky本身不支持稀疏输入
注意:np.linalg.cholesky返回的是下三角矩阵L,满足A = LLᵀ;若需上三角,得手动转置,别误用np.linalg.cholesky(A.T)——那会失败,因A.T与A相同(对称阵)。
多线程加速无效,但dtype选择影响显著
np.linalg.cholesky底层调用LAPACK,其并行行为由OpenBLAS或Intel MKL运行时控制,**不是**通过Python多线程触发。你在代码里开4个线程调用4次cholesky,不会比串行快——反而因线程争抢BLAS资源更慢。
真正能提速的是数据类型:
- 双精度
float64是默认,但若原始数据本就是float32(如图像特征协方差),强制转float64徒增内存且无精度收益 - 用
A.astype(np.float32, copy=False)预处理,分解速度通常提升1.5–2倍,内存减半 - 但要注意:
float32下正定性检验阈值需放宽(如用1e-6代替1e-10)
分解后解线性方程组的正确链式调用
Cholesky常用于求解Ax=b。别写np.linalg.solve(A, b)——那是通用LU,浪费已知的正定结构。
应分两步利用L:
- 先解Ly = b(前向代入):
y = scipy.linalg.solve_triangular(L, b, lower=True) - 再解Lᵀx = y(后向代入):
x = scipy.linalg.solve_triangular(L.T, y, lower=False)
注意:np.linalg.solve_triangular不存在,必须用scipy.linalg;且lower=True对应L,lower=False对应L.T(不是L.T再设lower=True)。
如果只需求L用于后续多次乘法(如采样),记住L是下三角,用L @ x即可,无需补零或填充。


















