Câu trả lời:
Đúng. Christopher Baker đã triển khai phương pháp SVD gia tăng của mình trong gói MATLAB có tên IncPACK ( được lưu trữ trên GitHub, trong dự án imtsl ). Nó thực hiện các phương pháp được mô tả trong luận án thạc sĩ của mình . Một cuộc thảo luận ngắn gọn về lý do tại sao thuật toán của Brand có xu hướng tích lũy lỗi có thể được tìm thấy trong một bài báo năm 2012 của Baker, et al . Một phương pháp liên quan của Chahlaoui, et al thảo luận về các giới hạn lỗi trên không gian con số ít bên trái và các giá trị số ít.
Tôi đã đề cập những điểm này trong các ý kiến về câu trả lời của Stephen, nhưng nó mang lặp đi lặp lại rằng phương pháp của cả hai Baker và bởi quy mô Chahlaoui như cho một cắt ngắn rank- SVD của một bởi ma trận . Đối với các xấp xỉ thứ hạng thấp, thuật ngữ chiếm ưu thế và, tùy thuộc vào biến thể thuật toán, có hằng số dẫn đầu thường nằm trong khoảng từ 8 đến 12.
Giống như câu trả lời của Stephen, thuật toán của Chahlaoui bắt đầu bằng nhân tố QR. Câu trả lời của Stephen sẽ có tác dụng tính toán các vectơ số đơn bên trái, nhưng một SVD dày đặc của ma trận sẽ có độ phức tạp siêu tuyến tính trong và trước khi cắt (nó sẽ là ), có thể sẽ làm giảm hiệu quả, nhưng có thể sẽ làm giảm hiệu quả, nhưng chính xác hơn
Để biết giá trị của nó, tôi đã tự mình thực hiện thuật toán của Brand và nó hơi nhạy cảm với dung sai sản phẩm bên trong được sử dụng để cắt giảm thứ hạng. Tôi chưa sử dụng gói của Baker, nhưng tôi tin rằng nó sẽ tốt hơn, vì các ước tính lỗi tồn tại cho thuật toán của Baker (hoặc liên quan chặt chẽ) và không phải là thuật toán của Brand và vì dung sai cắt giảm thứ hạng cho thuật toán của Baker là trên các giá trị đơn lẻ, không phải bên trong các sản phẩm.
seqkl
chức năng có vẻ như là chức năng chính, và có các tùy chọn cho đèo duy nhất và nhiều. Một lượt đi được đưa ra bởi seqkl_stdpass
, cuộc gọi nào seqkl_update
, vì vậy bạn có thể muốn sử dụng seqkl
cho một hệ số ban đầu, theo sau là các cuộc gọi để seqkl_update
cập nhật cột.
Một phương pháp để tính toán svd của ma trận X
là yếu tố đầu tiên X=QR
sử dụng phân tách QR (để ổn định, sử dụng xoay vòng, vì vậy đây là [Q,R,E] = qr(X,0)
trong Matlab), sau đó tính toán svd của R
. Nếu ma trận rất hình chữ nhật, thì tính toán đắt nhất là hệ số QR.
Do đó, nếu bạn tăng ma trận của mình X
bằng một hàng hoặc cột khác (đây là ý của bạn, phải không?), Bạn chỉ có thể cập nhật hệ số QR với qrinsert
chức năng của Matlab , sau đó thực hiện lại phép tính SVD R
.
Nếu bạn có một ma trận vuông lớn, phương pháp này sẽ không hữu ích, vì việc thực hiện lại SVD R
sẽ tốn thời gian.
Đây là một phương pháp có thể xử lý các bổ sung cột: http://pcc.byu.edu/resource.html . Tôi đã cập nhật nó để xử lý các bổ sung hàng:
function [Up1,Sp,Vp1] = addblock_svd_update2( Uarg, Sarg, Varg, Aarg, force_orth )
U = Varg;
V = Uarg;
S = Sarg;
A = Aarg';
current_rank = size( U, 2 );
m = U' * A;
p = A - U*m;
P = orth( p );
P = [ P zeros(size(P,1), size(p,2)-size(P,2)) ];
Ra = P' * p;
z = zeros( size(m) );
K = [ S m ; z' Ra ];
[tUp,tSp,tVp] = svds( K, current_rank );
Sp = tSp;
Up = [ U P ] * tUp;
Vp = V * tVp( 1:current_rank, : );
Vp = [ Vp ; tVp( current_rank+1:size(tVp,1), : ) ];
if ( force_orth )
[UQ,UR] = qr( Up, 0 );
[VQ,VR] = qr( Vp, 0 );
[tUp,tSp,tVp] = svds( UR * Sp * VR', current_rank );
Up = UQ * tUp;
Vp = VQ * tVp;
Sp = tSp;
end;
Up1 = Vp;
Vp1 = Up;
return;
Kiểm tra nó với
X = [[ 2.180116 2.493767 -0.047867;
-1.562426 2.292670 0.139761;
0.919099 -0.887082 -1.197149;
0.333190 -0.632542 -0.013330]];
A = [1 1 1];
X2 = [X; A];
[U,S,V] = svds(X);
[Up,Sp,Vp] = addblock_svd_update2(U, S, V, A, true);
Up
Sp
Vp
[U2,S2,V2] = svds(X2);
U2
S2
V2
Bạn sẽ thấy kết quả U, S, V ở cả hai bên là như nhau.
Cũng là phiên bản Python,
import numpy as np
import scipy.linalg as lin
def addblock_svd_update( Uarg, Sarg, Varg, Aarg, force_orth = False):
U = Varg
V = Uarg
S = np.eye(len(Sarg),len(Sarg))*Sarg
A = Aarg.T
current_rank = U.shape[1]
m = np.dot(U.T,A)
p = A - np.dot(U,m)
P = lin.orth(p)
Ra = np.dot(P.T,p)
z = np.zeros(m.shape)
K = np.vstack(( np.hstack((S,m)), np.hstack((z.T,Ra)) ))
tUp,tSp,tVp = lin.svd(K);
tUp = tUp[:,:current_rank]
tSp = np.diag(tSp[:current_rank])
tVp = tVp[:,:current_rank]
Sp = tSp
Up = np.dot(np.hstack((U,P)),tUp)
Vp = np.dot(V,tVp[:current_rank,:])
Vp = np.vstack((Vp, tVp[current_rank:tVp.shape[0], :]))
if force_orth:
UQ,UR = lin.qr(Up,mode='economic')
VQ,VR = lin.qr(Vp,mode='economic')
tUp,tSp,tVp = lin.svd( np.dot(np.dot(UR,Sp),VR.T));
tSp = np.diag(tSp)
Up = np.dot(UQ,tUp)
Vp = np.dot(VQ,tVp)
Sp = tSp;
Up1 = Vp;
Vp1 = Up;
return Up1,Sp,Vp1
Một thay thế cho SVD tăng dần là HAPOD phân rã trực giao gần đúng theo thứ bậc , trong đó có thể tìm thấy một triển khai trên github: http://git.io/hapod . HAPOD có giới hạn lỗi nghiêm ngặt và trường hợp đặc biệt là một biến thể gia tăng.