回答:
はい。Christopher Bakerは、彼のインクリメンタルSVDメソッドを、IncPACK(imtslプロジェクト内のGitHubにアーカイブされている)と呼ばれるMATLABパッケージに実装しました。それは彼の修士論文に記載されているメソッドを実装しています。ブランドのアルゴリズムがエラーを蓄積する傾向がある理由の簡単な説明は、ベーカーらによる2012年の論文に記載されています。Chahlaouiらによる関連する方法は、左特異部分空間のエラー限界と特異値を議論します。
私はすでにスティーブンの答えのコメントでは、これらの点を言及したが、それは繰り返しクマとの両方BakerのとChahlaouiスケールによる方法トランケートrank-ためのK SVDのMによってn行列。低ランクの近似の場合、m n k項が支配的であり、アルゴリズムのバリアントに応じて、通常8〜12の先行定数があります。
スティーブンの答えと同様に、チャラウイのアルゴリズムはQR分解から始まります。スティーブンの答えは左特異ベクトルの計算に役立ちますが、行列の密なSVDは、切り捨て前にmとnで超線形の複雑さを持ち(O (m n 2)になる)、これはおそらく効率を低下させますが、より高くなります正確。
それだけの価値があるので、私はブランドのアルゴリズムを自分で実装しました。これは、ランクの切り捨てに使用される内積許容値に多少敏感です。私はベイカーのパッケージを使用していませんが、ブランドのアルゴリズムではなく、ベイカーのアルゴリズム(または密接に関連しているアルゴリズム)のエラー推定が存在し、ベイカーのアルゴリズムのランク切り捨て許容値が内部ではなく特異値にあるため、より良いと思います製品。
seqkl
関数はメイン関数のように見え、単一パスと複数パスのオプションがあります。シングルパスはによって与えられseqkl_stdpass
、を呼び出しますseqkl_update
。そのため、おそらくseqkl
最初の因数分解に使用し、その後seqkl_update
に列の更新を呼び出すことをお勧めします。
行列のsvdを計算する1つの方法X
は、最初X=QR
にQR分解を使用して因数分解する(安定性のためにピボットを使用するため、これは[Q,R,E] = qr(X,0)
Matlabにあります)、次にのsvdを計算しR
ます。どちらかの行列が非常に長方形である場合、最もコストのかかる計算はQR分解です。
したがって、マトリックスX
を別の行または列でインクリメントする場合(これはあなたが意図したとおりのことです)、Qt分解をMatlabのqrinsert
関数で更新し、のSVD計算をやり直すことができR
ます。
大きな正方行列がある場合、SVDの再実行にはR
時間がかかるため、この方法はあまり役に立ちません。
列の追加を処理できるメソッドは次のとおりです:http : //pcc.byu.edu/resources.html。行の追加を処理するように更新しました。
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;
でテストする
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
両側のU、S、Vの結果が同じであることがわかります。
また、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