numpy.linalg.svd 是 numpy 中唯一推荐的 svd 函数,返回 u、s(一维数组)、vh 三元组;s 非方阵是为节省内存并适配截断需求,重建时推荐 (u * s) @ vh 而非 u @ np.diag(s) @ vh 以避免冗余内存开销。

numpy.linalg.svd 是 NumPy 中做 SVD 分解的唯一推荐函数,它返回 U、s、Vh 三部分,不是 U、S、V.T 的“教科书形式”——这点不注意会直接导致矩阵乘法还原失败。
为什么 svd 返回的 s 不是方阵?
NumPy 默认返回的是奇异值一维数组 s,而非对角矩阵 S。这是为了节省内存和适配不同计算场景(比如只取前 k 个奇异值)。如果你需要重建原始矩阵,得手动用 np.diag(s) 或更高效地用 np.outer / np.einsum 拼接,但更常见、更安全的做法是用 full_matrices=False 配合广播规则还原:
-
U是m × min(m,n),Vh是min(m,n) × n,s是长度为min(m,n)的向量 - 还原时写成
U @ np.diag(s) @ Vh可行,但构造np.diag(s)会临时生成一个min(m,n) × min(m,n)矩阵,大矩阵下浪费内存 - 推荐用
(U * s) @ Vh:利用广播,U形状为(m, k),s为(k,),U * s是逐列缩放,再右乘Vh,零额外内存开销
如何控制输出矩阵大小(full_matrices 参数)
这个布尔参数决定 U 和 Vh 是否补零到“完整正交基”。默认是 True,但绝大多数实际用途(如降维、推荐系统、图像压缩)都该设为 False:
-
full_matrices=True(默认):U是m × m,Vh是n × n—— 对m=10000的矩阵,U就占约 800MB 内存(float64) -
full_matrices=False:U是m × k,Vh是k × n,其中k = min(m,n),内存和计算量大幅下降 - 只有在需要完整左/右奇异向量(例如某些数值分析验证)时才用
True
遇到 LinAlgError: SVD did not converge 怎么办
这不是数据问题,而是底层 LAPACK 实现对病态矩阵或低秩近似失败的报错。常见于含大量零、重复行/列,或 dtype 为 float32 且条件数高的矩阵:
- 先检查
A.dtype,强制转成float64:用A.astype(np.float64)再调用svd - 对稀疏或含零多的矩阵,提前中心化或标准化(如减均值、除标准差),有时能改善收敛性
- 若只需前 k 个奇异值/向量,别用完整
svd,改用scipy.sparse.linalg.svds(支持k )或 <code>sklearn.decomposition.TruncatedSVD - 极少数情况可加小扰动:
A += np.random.normal(0, 1e-12, A.shape),仅用于调试,不可用于生产数据
真正容易被忽略的是:SVD 结果的符号不确定性——U 和 Vh 的对应列可能整体变号,不影响分解正确性,但会导致多次运行结果不一致;如果后续依赖向量方向(如聚类、可视化),需手动对齐符号(例如让每列第一个非零元为正)。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











