我的例子显示SVD在数值上比QR分解更不稳定

时间:2016-04-06 13:31:58

标签: matlab least-squares svd matrix-decomposition qr-decomposition

我在Math Stackexchange中问过这个问题,但似乎没有得到足够的关注,所以我在这里问它。 https://math.stackexchange.com/questions/1729946/why-do-we-say-svd-can-handle-singular-matrx-when-doing-least-square-comparison?noredirect=1#comment3530971_1729946

我从一些教程中了解到,当求解最小二乘问题时,SVD应该比QR分解更稳定,并且它能够处理奇异矩阵。但是我在matlab中编写的以下示例似乎支持相反的结论。我对SVD没有深刻的理解,所以如果您可以在Math StackExchange的旧帖子中查看我的问题并向我解释,我会非常感激。

我使用具有大条件数(e + 13)的矩阵。结果显示SVD比QR(e-27)得到更大的误差(0.8)

% we do a linear regression between Y and X
data= [
47.667483331 -122.1070832;
47.667483331001 -122.1070832
];
X = data(:,1);
Y = data(:,2);

X_1 =  [ones(length(X),1),X];

%%
%SVD method
[U,D,V] = svd(X_1,'econ');
beta_svd = V*diag(1./diag(D))*U'*Y;


%% QR method(here one can also use "\" operator, which will get the same result as I tested. I just wrote down backward substitution to educate myself)
[Q,R] = qr(X_1)
%now do backward substitution
[nr nc] = size(R)
beta_qr=[]
Y_1 = Q'*Y
for i = nc:-1:1
    s = Y_1(i)
    for j = m:-1:i+1
        s = s - R(i,j)*beta_qr(j)
    end
    beta_qr(i) = s/R(i,i)
end

svd_error = 0;
qr_error = 0;
for i=1:length(X)
   svd_error = svd_error + (Y(i) - beta_svd(1) - beta_svd(2) * X(i))^2;
   qr_error = qr_error + (Y(i) - beta_qr(1) - beta_qr(2) * X(i))^2;
end

2 个答案:

答案 0 :(得分:5)

基于SVD的方法与MATLAB中的pinv function基本相同(参见Pseudo-inverse and SVD)。你所缺少的(出于数字原因)是使用公差值,使得小于此公差的任何奇异值都被视为零。

如果你引用edit pinv.m,你会看到如下内容(我不会在此发布确切的代码,因为该文件的版权归MathWorks所有):

[U,S,V] = svd(A,'econ');
s = diag(S);
tol = max(size(A)) * eps(norm(s,inf));
% .. use above tolerance to truncate singular values
invS = diag(1./s);
out = V*invS*U';

事实上,pinv有第二种语法,如果默认值不合适,您可以明确指定容差值pinv(A,tol) ...

因此,在解决minimize norm(A*x-b)形式的最小二乘问题时,您应该了解pinvmldivide解决方案具有不同的属性:

  • x = pinv(A)*b的特点是norm(x)小于任何其他解决方案的标准。
  • x = A\b具有尽可能少的非零成分(即稀疏)。

使用您的示例(请注意rcond(A)在机器epsilon附近非常小)

data = [
    47.667483331    -122.1070832;
    47.667483331001 -122.1070832
];
A = [ones(size(data,1),1), data(:,1)];
b = data(:,2);

让我们比较两种解决方案:

x1 = A\b;
x2 = pinv(A)*b;

首先,你可以看到mldivide如何返回一个零分量的解x1(这显然是一个有效的解决方案,因为你可以通过乘以b + a*0 = b中的零来解决这两个方程式) :

>> sol = [x1 x2]
sol =
 -122.1071   -0.0537
         0   -2.5605

接下来,您会看到pinv如何返回具有较小规范的解决方案x2

>> nrm = [norm(x1) norm(x2)]
nrm =
  122.1071    2.5611

这两个解决方案的错误是可接受的非常小:

>> err = [norm(A*x1-b) norm(A*x2-b)]
err =
   1.0e-11 *
         0    0.1819

请注意,使用mldividelinsolveqr会得到几乎相同的结果:

>> x3 = linsolve(A,b)
Warning: Matrix is close to singular or badly scaled. Results may be inaccurate. RCOND =  2.159326e-16. 
x3 =
 -122.1071
         0

>> [Q,R] = qr(A); x4 = R\(Q'*b)
x4 =
 -122.1071
         0

答案 1 :(得分:2)

尝试这个称为块SVD的SVD版本 - 您只需将迭代设置为您想要的精度 - 通常1就足够了。如果你想要所有的因素(这有一个默认的#选择用于因子减少)然后编辑线k =到大小(矩阵)如果我正确地回忆我的MATLAB

A= randn(100,5000);
A=corr(A);
% A is your correlation matrix
tic
k = 1000; % number of factors to extract
bsize = k +50;
block = randn(size(A,2),bsize);
iter = 2; % could set via tolerance

[block,R] = qr(A*block,0);
for i=1:iter
    [block,R] = qr(A*(A'*block),0);
end
M = block'*A;
% Economy size dense SVD.
[U,S] = svd(M,0);
U = block*U(:,1:k);
S = S(1:k,1:k);
% Note SVD of a symmetric matrix is:
% A = U*S*U' since V=U in this case, S=eigenvalues, U=eigenvectors
V=real(U*sqrt(S)); %scaling matrix for simulation
toc
% reduced randomized matrix for simulation
sims = 2000;
randnums = randn(k,sims);
corrrandnums = V*randnums;
est_corr_matrix = corr(corrrandnums');
total_corrmatrix_difference =sum(sum(est_corr_matrix-A))