Analyse du problème
La SVD d'une matrice n'est jamais unique. Soit la matrice dimensions et que sa SVD soitn × kAn×k
A=UDV′
pour un la matrice avec des colonnes orthonormales, une diagonale la matrice avec des entrées non-négatives, et un la matrice avec des colonnes orthonormales.U p × p D k × p Vn×pUp×pDk×pV
Maintenant, choisissez arbitrairement n'importe quelle diagonale matrice ayant s sur la diagonale, de sorte que soit l' identité . alorsS ± 1 S 2 = I p × p I pp×pS±1S2=Ip×pIp
A=UDV′=UIDIV′=U(S2)D(S2)V′=(US)(SDS)(VS)′
est également un SVD de parce que montre que a des colonnes orthonormées et un calcul similaire montre que a des colonnes orthonormées. De plus, puisque et sont diagonaux, ils font la navette, d'où montre que toujours des entrées non négatives.( U S ) ′ ( U S ) = S ′ U ′ U S = S ′ I p S = S ′ S = S 2 = I p U S V S S D S D S = D S 2 = D DA
(US)′(US)=S′U′US=S′IpS=S′S=S2=Ip
USVSSDSDS=DS2=D
D
La méthode implémentée dans le code pour trouver un SVD trouve un qui diagonalise et, de la même façon, un qui diagonale Il procède au calcul de en fonction des valeurs propres trouvées dans . Le problème est que cela ne garantit pas une correspondance cohérente des colonnes de avec les colonnes de .A A ′ = ( U D V ′ ) ( U D V ′ ) ′ = U D V ′ V D ′ U ′ = U D 2 U ′ V A ′ A = V D 2 V ′ . D D 2 U VU
AA′=(UDV′)(UDV′)′=UDV′VD′U′=UD2U′
VA′A=VD2V′.
DD2UV
Une solution
Au lieu de cela, après avoir trouvé un tel et un tel , utilisez-les pour calculerVUV
U′AV=U′(UDV′)V=(U′U)D(V′V)=D
directement et efficacement. Les valeurs diagonales de ce ne sont pas nécessairement positives. D (C'est parce qu'il n'y a rien dans le processus de diagonalisation de ou qui garantira que, puisque ces deux processus ont été effectués séparément.) Rendez-les positifs en choisissant les entrées le long de la diagonale de pour égaler les signes des entrées de , de sorte que ait toutes les valeurs positives. Compensez cela en multipliant à droite par :A′AAA′SDSDUS
A=UDV′=(US)(SD)V′.
C'est un SVD.
Exemple
Soit avec . Un SVD estn=p=k=1A=(−2)
(−2)=(1)(2)(−1)
avec , et .U=(1)D=(2)V=(−1)
Si vous diagonalisezA′A=(4)U=(1)D=(4–√)=(2)AA′=(4)V=(1)
UDV′=(1)(2)(1)=(2)≠A.
D=U′AV=(1)′(−2)(1)=(−2).
S=(−1)UUS=(1)(−1)=(−1)DSD=(−1)(−2)=(2)A=(−1)(2)(1),
Code
Voici le code modifié. Sa sortie confirme
- La méthode recrée
m
correctement.
- U et sont vraiment encore orthonormés.V
- Mais le résultat n'est pas le même SVD renvoyé par
svd
. (Les deux sont également valables.)
m <- matrix(c(1,0,1,2,1,1,1,0,0),byrow=TRUE,nrow=3)
U <- eigen(tcrossprod(m))$vector
V <- eigen(crossprod(m))$vector
D <- diag(zapsmall(diag(t(U) %*% m %*% V)))
s <- diag(sign(diag(D))) # Find the signs of the eigenvalues
U <- U %*% s # Adjust the columns of U
D <- s %*% D # Fix up D. (D <- abs(D) would be more efficient.)
U1=svd(m)$u
V1=svd(m)$v
D1=diag(svd(m)$d,n,n)
zapsmall(U1 %*% D1 %*% t(V1)) # SVD
zapsmall(U %*% D %*% t(V)) # Hand-rolled SVD
zapsmall(crossprod(U)) # Check that U is orthonormal
zapsmall(tcrossprod(V)) # Check that V' is orthonormal