Compute the singular-value decomposition of a matrix \(X\) either by Jacobi
rotations (the default) or from the eigenstructure of \(X'X\) using
Eigen
. Both methods are iterative.
The result consists of two orthonormal matrices, \(U\), and \(V\) and the vector \(d\)
of singular values, such that \(X = U diag(d) V'\).
Value
a list of three elements: d
– singular values, U
– left singular vectors, V
– right singular vectors
Details
The default method is more numerically stable, but the eigenstructure method is much simpler. Singular values of zero are not retained in the solution.
Examples
C <- matrix(c(1,2,3,2,5,6,3,6,10), 3, 3) # nonsingular, symmetric
C
#> [,1] [,2] [,3]
#> [1,] 1 2 3
#> [2,] 2 5 6
#> [3,] 3 6 10
SVD(C)
#> $d
#> [1] 14.93303437 1.00000000 0.06696563
#>
#> $U
#> [,1] [,2] [,3]
#> [1,] 0.2505248 4.308756e-14 0.9681102
#> [2,] 0.5370109 8.320503e-01 -0.1389662
#> [3,] 0.8055164 -5.547002e-01 -0.2084492
#>
#> $V
#> [,1] [,2] [,3]
#> [1,] 0.2505248 2.960306e-15 0.9681102
#> [2,] 0.5370109 8.320503e-01 -0.1389662
#> [3,] 0.8055164 -5.547002e-01 -0.2084492
#>
# least squares by the SVD
data("workers")
X <- cbind(1, as.matrix(workers[, c("Experience", "Skill")]))
head(X)
#> Experience Skill
#> Abby 1 0 2
#> Betty 1 5 5
#> Charles 1 5 8
#> Doreen 1 10 6
#> Ethan 1 10 10
#> Francie 1 15 7
y <- workers$Income
head(y)
#> [1] 20 35 40 30 50 50
(svd <- SVD(X))
#> $d
#> [1] 66.864276 8.885751 1.100924
#>
#> $U
#> Experience Skill
#> Abby 0.01366778 0.21621629 0.62512040
#> Betty 0.10046906 0.26924846 0.34867115
#> Charles 0.12007689 0.56866664 -0.06013463
#> Doreen 0.17419846 0.12266851 0.34475908
#> Ethan 0.20034223 0.52189275 -0.20031530
#> Francie 0.24792785 -0.02391144 0.34084702
#> Georges 0.34780102 0.22873284 -0.20813943
#> Harry 0.40192259 -0.21726529 0.19675429
#> Isaac 0.50179576 0.03537900 -0.35223216
#> Juan 0.55591732 -0.41061914 0.05266156
#>
#> $V
#> [,1] [,2] [,3]
#> [1,] 0.03984368 0.1475406 0.98825314
#> [2,] 0.89856830 -0.4378649 0.02914291
#> [3,] 0.43702116 0.8868518 -0.15002142
#>
VdU <- svd$V %*% diag(1/svd$d) %*%t(svd$U)
(b <- VdU %*% y)
#> [,1]
#> [1,] 14.7808811
#> [2,] 0.1130069
#> [3,] 3.4053991
coef(lm(Income ~ Experience + Skill, data=workers))
#> (Intercept) Experience Skill
#> 14.7808811 0.1130069 3.4053991