基于SVD的矩阵近似与原矩阵Frobenius范数计算异常排查
奇异值分解(SVD)近似的Frobenius范数误差问题
你这里的问题根源是对《信息检索》中定理18.4的理解有点偏差哦!
先明确定理的准确内容:当我们通过将矩阵的t个最小奇异值置零得到秩为k(k = 原矩阵秩 - t)的近似矩阵时,原矩阵与近似矩阵的Frobenius范数误差的平方,等于所有被置零的奇异值的平方之和。用公式表示就是:
$$|A - A_k|F^2 = \sum{i=k+1}^r \sigma_i^2$$
其中$r$是原矩阵的秩,$\sigma_i$是按降序排列的奇异值
回到你的例子:
- 原矩阵的奇异值是
array([2.16250096, 1.59438237, 1.27529025, 1. , 0.39391525]) - 你把第4和第5个奇异值(也就是1和0.39391525)置零了,相当于移除了这两个奇异值
那误差的平方应该是:1² + (0.39391525)² ≈ 1 + 0.1551 ≈ 1.1551
对这个值开根号,得到的结果就是≈1.075,这和你代码中计算出的1.07完全吻合!
你之前误以为误差等于被移除的最大奇异值(也就是1),但实际上定理要求的是所有被置零的奇异值的平方和的平方根,这才是正确的Frobenius误差计算方式。
再用代码验证一下这个结论:
import numpy as np la = np.linalg a = np.array([[1,0,1,0,0,0], [0,1,0,0,0,0], [1,1,0,0,0,0], [1,0,0,1,1,0], [0,0,0,1,0,1]]) svd = la.svd(a, full_matrices=False) U = svd[0] S = np.diag(svd[1]) Vt = svd[2] # 置零第4、5个奇异值 S[3,3] = 0 S[4,4] = 0 b = np.dot(np.dot(U, S), Vt) # 计算误差的平方 error_squared = la.norm(a-b)**2 # 计算被置零的奇异值平方和 removed_sq_sum = (1.0)**2 + (0.39391525)**2 print(error_squared) # 输出≈1.155 print(removed_sq_sum) # 输出≈1.155
两者结果完全一致,这也证明了你的代码本身没有问题,只是对定理的理解出现了小偏差~
内容的提问来源于stack exchange,提问作者Hossein
相关产品推荐
相关产品推荐

