day*_*yup 3 matlab svd least-squares qr-decomposition matrix-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
Run Code Online (Sandbox Code Playgroud)
基于SVD的方法与MATLAB中的pinv函数基本相同(参见伪逆和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';
Run Code Online (Sandbox Code Playgroud)
实际上pinv有第二种语法,pinv(A,tol)如果默认值不合适,你可以明确指定容差值......
因此,在解决表单的最小二乘问题时minimize norm(A*x-b),您应该理解pinv和mldivide解决方案具有不同的属性:
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);
Run Code Online (Sandbox Code Playgroud)
让我们比较两种解决方案:
x1 = A\b;
x2 = pinv(A)*b;
Run Code Online (Sandbox Code Playgroud)
首先,你可以看到如何mldivide返回x1一个零分量的解决方案(这显然是一个有效的解决方案,因为你可以通过乘以零来解决这两个方程式b + a*0 = b):
>> sol = [x1 x2]
sol =
-122.1071 -0.0537
0 -2.5605
Run Code Online (Sandbox Code Playgroud)
接下来,您将了解如何pinv返回x2具有较小规范的解决方案:
>> nrm = [norm(x1) norm(x2)]
nrm =
122.1071 2.5611
Run Code Online (Sandbox Code Playgroud)
这两个解决方案的错误是可接受的非常小:
>> err = [norm(A*x1-b) norm(A*x2-b)]
err =
1.0e-11 *
0 0.1819
Run Code Online (Sandbox Code Playgroud)
请注意,使用mldivide,, linsolve或qr将给出几乎相同的结果:
>> 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
Run Code Online (Sandbox Code Playgroud)