Análisis del Problema
El SVD de la matriz nunca es único. Vamos matriz A tiene dimensiones de la n×k y deje que su enfermedad vesicular porcina ser
A=UDV′
for an n×p matrix U with orthonormal columns, a diagonal p×p matrix D with non-negative entries, and a k×p matrix V with orthonormal columns.
Now choose, arbitrarily, any diagonal p×p matrix S having ±1s on the diagonal, so that S2=I is the p×p identity Ip. Then
A=UDV′=UIDIV′=U(S2)D(S2)V′=(US)(SDS)(VS)′
is also an SVD of A because (US)′(US)=S′U′US=S′IpS=S′S=S2=Ip demonstrates US has orthonormal columns and a similar calculation demonstrates VS has orthonormal columns. Moreover, since S and D are diagonal, they commute, whence SDS=DS2=D shows D still has non-negative entries.
The method implemented in the code to find an SVD finds a U that diagonalizes AA′=(UDV′)(UDV′)′=UDV′VD′U′=UD2U′ and, similarly, a V that diagonalizes A′A=VD2V′. It proceeds to compute D in terms of the eigenvalues found in D2. The problem is this does not assure a consistent matching of the columns of U with the columns of V.
A Solution
Instead, after finding such a U and such a V, use them to compute
U′AV=U′(UDV′)V=(U′U)D(V′V)=D
directly and efficiently. The diagonal values of this D are not necessarily positive. (That is because there is nothing about the process of diagonalizing either A\elprimerA or AA′ that will guarantee that, since those two processes were carried out separately.) Make them positive by choosing the entries along the diagonal of S to equal the signs of the entries of D, so that SD has all positive values. Compensate for this by right-multiplying U by S:
A=UDV′=(US)(SD)V′.
That is an SVD.
Example
Let n=p=k=1 with A=(−2). An SVD is
(−2)=(1)(2)(−1)
with U=(1), D=(2), and V=(−1).
If you diagonalize A\primerA=(4) you would naturally choose U=(1) and D=(√4)=(2). Likewise if you diagonalize AA′=(4) you would choose V=(1). Unfortunately, UDV′=(1)(2)(1)=(2)≠A. Instead, compute D=U′AV=(1)′(−2)(1)=(−2). Because this is negative, set S=(−1). This adjusts U to EstadosUnidos=(1)(−1)=(−1) and D to SD=(−1)(−2)=(2). You have obtained A=(−1)(2)(1), que es uno de los dos posibles SVDs (pero no el mismo que el original!).
Código
Aquí es el código modificado. Su salida se confirma
- El método recrea
m
correctamente.
- U V realmente todavía son ortonormales.
- Pero el resultado no es el mismo de enfermedad vesicular porcina devuelto por
svd
. (Ambos son igualmente válidas.)
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