我的例子表明 SVD 在数值上不如 QR 分解稳定
My example shows SVD is less numerically stable than 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 的旧 post 中查看我的问题并向我解释,我将不胜感激。
我使用的矩阵具有较大的条件数 (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
SVD 可以处理秩不足。对角矩阵 D 在您的代码中有一个接近零的元素,您需要对 SVD 使用伪逆,即将 1./diag(D) 的第二个元素设置为 0,而不是巨大的值 (10^14)。您应该发现 SVD 和 QR 在您的示例中具有同样好的准确性。有关详细信息,请参阅此文档 http://www.cs.princeton.edu/courses/archive/fall11/cos323/notes/cos323_f11_lecture09_svd.pdf
你基于SVD的方法与pinv
function in MATLAB (see Pseudo-inverse and SVD)基本相同。但是(由于数字原因)您缺少的是使用公差值,这样任何小于此公差的奇异值都被视为零。
如果你参考 edit pinv.m
,你可以看到类似下面的内容(我不会 post 这里的确切代码,因为该文件受 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)
形式的最小二乘问题时,您应该了解 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);
让我们比较一下两种解决方案:
x1 = A\b;
x2 = pinv(A)*b;
首先你可以看到 mldivide
returns 解 x1
有一个零分量(这显然是一个有效的解,因为你可以通过乘以零来解两个方程b + a*0 = b
):
>> sol = [x1 x2]
sol =
-122.1071 -0.0537
0 -2.5605
接下来你会看到 pinv
returns 一个更小范数的解 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
请注意,使用 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
尝试这个称为块 SVD 的 SVD 版本 - 您只需将迭代设置为等于您想要的精度 - 通常 1 就足够了。如果你想要所有的因素(这有一个默认的# selected for factor reduction)然后编辑行 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))
我在 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 的旧 post 中查看我的问题并向我解释,我将不胜感激。
我使用的矩阵具有较大的条件数 (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
SVD 可以处理秩不足。对角矩阵 D 在您的代码中有一个接近零的元素,您需要对 SVD 使用伪逆,即将 1./diag(D) 的第二个元素设置为 0,而不是巨大的值 (10^14)。您应该发现 SVD 和 QR 在您的示例中具有同样好的准确性。有关详细信息,请参阅此文档 http://www.cs.princeton.edu/courses/archive/fall11/cos323/notes/cos323_f11_lecture09_svd.pdf
你基于SVD的方法与pinv
function in MATLAB (see Pseudo-inverse and SVD)基本相同。但是(由于数字原因)您缺少的是使用公差值,这样任何小于此公差的奇异值都被视为零。
如果你参考 edit pinv.m
,你可以看到类似下面的内容(我不会 post 这里的确切代码,因为该文件受 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)
形式的最小二乘问题时,您应该了解 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);
让我们比较一下两种解决方案:
x1 = A\b;
x2 = pinv(A)*b;
首先你可以看到 mldivide
returns 解 x1
有一个零分量(这显然是一个有效的解,因为你可以通过乘以零来解两个方程b + a*0 = b
):
>> sol = [x1 x2]
sol =
-122.1071 -0.0537
0 -2.5605
接下来你会看到 pinv
returns 一个更小范数的解 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
请注意,使用 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
尝试这个称为块 SVD 的 SVD 版本 - 您只需将迭代设置为等于您想要的精度 - 通常 1 就足够了。如果你想要所有的因素(这有一个默认的# selected for factor reduction)然后编辑行 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))