下面是我的测试函数:
function diff = svdtester()
y = rand(500,20);
[U,S,V] = svd(y);
%{
y = sprand(500,20,.1);
[U,S,V] = svds(y);
%}
diff_mat = y - U*S*V';
diff = mean(abs(diff_mat(:)));
end
有两个非常相似的部分:一个是求随机矩阵的SVD,另一个是求随机稀疏矩阵的SVD。不管你选择注释哪一个(现在第二个被注释掉了),我们计算原始矩阵和它的SVD分量的乘积之间的差,并返回平均绝对差。
使用rand/svd时,典型的返回(平均误差)值在8.8e-16左右,基本为零。当使用sprand/svds时,典型的返回值约为0.07,考虑到稀疏矩阵开始时90%是0,这是相当可怕的。
我是否误解了SVD应该如何为稀疏矩阵工作,还是这些函数有问题?
是的,svds
的行为与svd
略有不同。根据MATLAB的文档:
[U,S,V] = svds(A,...)
返回三个输出参数,如果A
是m
-by-n
:
U
是具有正交列的m
-by-k
S
是k
-by-k
对角线
V
是具有正交列的n
-by-k
U*S*V'
是A
最接近k
的秩
事实上,通常k
将是6
的一些东西,所以你会得到相当"粗略"的近似。为了获得更精确的近似,指定k
为min(size(y))
:
[U, S, V] = svds(y, min(size(y)))
,您将得到与svd
相同数量级的误差。
注:此外,MATLAB的文档说:
注意
svds
最适合用于查找大型稀疏矩阵的几个奇异值。为了找到这样一个矩阵的所有奇异值,svd(full(A))
通常会比svds(A,min(size(A)))
表现得更好。