numpy.linalg.svd 返回U、s、Vh三元组,s为降序一维数组,Vh是V的共轭转置;full_matrices=False更高效;重建需构造匹配形状的对角矩阵;处理小奇异值需设阈值防除零;结果符号不唯一。
NumPy 的 numpy.linalg.svd 是最直接、最可靠的 SVD 实现方式,它返回标准的 U、s、Vh 三元组,无需额外封装或手动拼接。
如何调用 numpy.linalg.svd 并理解返回值
该函数默认返回完整分解(full_matrices=True),但多数场景下你只需要“精简”形式。注意 s 是一维数组,不是对角矩阵;Vh 是 V 的共轭转置(即 Hermitian),不是 V 本身。
-
U是左奇异向量矩阵,形状为(m, m)(full)或(m, k)(reduced),列正交 -
s是奇异值数组,长度为min(m, n),按降序排列 -
Vh是右奇异向量的共轭转置,形状为(n, n)(full)或(k, n)(reduced) - 若只需降维或重建近似矩阵,务必设
full_matrices=False,否则内存和计算开销陡增
import numpy as np A = np.array([[1, 2, 3], [4, 5, 6]]) U, s, Vh = np.linalg.svd(A, full_matrices=False) # 推荐:节省空间 # 此时 U.shape == (2, 2), s.shape == (2,), Vh.shape == (2, 3)
重建原矩阵时为什么 U @ np.diag(s) @ Vh 不总是成立?
因为 np.diag(s) 生成的是方阵,而 U 和 Vh 在 full_matrices=False 下维度不匹配。必须手动扩展 s 成合适形状的中间矩阵,或用广播技巧。
Python 3.14.3
微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。
- 错误写法:
U @ np.diag(s) @ Vh→ 形状不兼容(如(2,2) @ (2,2) @ (2,3)中间结果是(2,2) @ (2,3)才对) - 正确做法:构造
(U.shape[1], Vh.shape[0])大小的零矩阵,再把s填入对角线 - 更简洁方式:用
np.zeros((U.shape[1], Vh.shape[0]))+np.fill_diagonal,或直接用np.einsum
# 安全重建(适用于 full_matrices=False) s_mat = np.zeros((U.shape[1], Vh.shape[0])) np.fill_diagonal(s_mat, s) A_recon = U @ s_mat @ Vh
处理非满秩或含零奇异值的矩阵时要注意什么?
numpy.linalg.svd 本身能稳定处理秩亏矩阵,但后续使用 s 时容易因数值误差触发除零或精度问题。
- 奇异值接近零(如
1e-16)不代表严格为零,取决于矩阵条件数和浮点精度 - 做伪逆或降维时,别直接用
1/s,应先设阈值截断小奇异值:s_inv = np.where(s > 1e-10, 1/s, 0) - 用
np.linalg.matrix_rank(A, tol=1e-10)辅助判断有效秩,比数s > 0更鲁棒 - 如果输入含
nan或inf,svd会报LinAlgError: SVD did not converge,需提前清洗
真正容易被忽略的是:SVD 结果不唯一——U 和 Vh 的符号可能翻转(只要保持 U @ diag(s) @ Vh 不变),不同 NumPy 版本或硬件上可能给出不同符号组合,这在跨环境比对结果时会引发误判。
就爱读