Análisis del problema
La SVD de una matriz nunca es única. Deje que la matriz tenga dimensiones y deje que su SVD sean × kAn×k
A=UDV′
para una matriz con columnas ortonormales, una diagonal matriz con entradas no negativas y una matriz con columnas ortonormales.U p × p D k × p Vn×pUp×pDk×pV
Ahora elija, arbitrariamente , cualquier diagonal matriz tenga s en la diagonal, de modo que sea la identidad . EntoncesS ± 1 S 2 = I p × p I pp×pS±1S2=Ip×pIp
A=UDV′=UIDIV′=U(S2)D(S2)V′=(US)(SDS)(VS)′
también es una SVD de porque demuestra que tiene columnas ortonormales y un cálculo similar demuestra que tiene columnas ortonormales. Además, dado que y son diagonales, conmutan, de donde muestra que todavía tiene entradas no negativas.A
(US)′(US)=S′U′US=S′IpS=S′S=S2=Ip
USVSSDSDS=DS2=D
D
El método implementado en el código para encontrar un SVD encuentra una que diagonaliza y, de manera similar, una que diagonaliza Se procede a calcular en términos de los valores propios encontrados en . El problema es esto no asegura un juego consistente de las columnas de con las columnas de .U
AA′=(UDV′)(UDV′)′=UDV′VD′U′=UD2U′
VA′A=VD2V′.
DD2UV
Una solución
En cambio, después de encontrar una y una , úselas para calcularUV
U′AV=U′(UDV′)V=(U′U)D(V′V)=D
directa y eficientemente Los valores diagonales de esta no son necesariamente positivos. D (Esto se debe a que no hay nada en el proceso de diagonalización de o que garantice eso, ya que esos dos procesos se llevaron a cabo por separado). Hazlos positivos eligiendo las entradas a lo largo de la diagonal de para igualar los signos de las entradas de , de modo que tenga todos los valores positivos. Compensar esto multiplicando a la derecha por :A′AAA′SDSDUS
A=UDV′=(US)(SD)V′.
Esa es una SVD.
Ejemplo
Sea con . Una SVD esn=p=k=1A=(−2)
(−2)=(1)(2)(−1)
con , y .U=(1)D=(2)V=(−1)
Si diagonaliza , naturalmente elegiría y . Del mismo modo, si diagonaliza , elegiría . Desafortunadamente, En cambio, calcule Como esto es negativo, establezca . Esto ajusta a y a . Ha obtenido que es uno de los dos SVD posibles (¡pero no el mismo que el original!).A′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),
Código
Aquí hay un código modificado. Su salida confirma
- El método se recrea
m
correctamente.
- U y realmente todavía son ortonormales.V
- Pero el resultado no es el mismo SVD devuelto por
svd
. (Ambos son igualmente válidos).
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