Introducción

La Descomposición en Valores Singulares (SVD, del inglés Singular Value Decomposition) es una factorización de cualquier matriz real \(A \in \mathbb{R}^{m \times n}\) como el producto de tres matrices:

\[A = U \, \Sigma \, V^T,\]

donde: - \(U \in \mathbb{R}^{m \times m}\) es una matriz ortogonal (sus columnas son los vectores singulares izquierdos). - \(V \in \mathbb{R}^{n \times n}\) es una matriz ortogonal (sus columnas son los vectores singulares derechos). - \(\Sigma \in \mathbb{R}^{m \times n}\) es una matriz diagonal cuyas entradas no nulas son los valores singulares \(\sigma_1 \ge \sigma_2 \ge \dots \ge \sigma_r > 0\), siendo \(r\) el rango de \(A\).

En este documento ilustraremos el proceso con un ejemplo numérico sencillo utilizando una matriz aleatoria de tamaño \(2 \times 4\) con entradas enteras.

Creación de la matriz de ejemplo

Comenzamos generando una matriz \(A \in \mathbb{R}^{2 \times 4}\) con números enteros aleatorios entre \(-5\) y \(5\) (para que los cálculos sean manejables). Fijamos una semilla para garantizar la reproducibilidad.

set.seed(2024)  # Para reproducibilidad
A <- matrix(sample(-5:5, size = 8, replace = TRUE), nrow = 2, ncol = 4)
dimnames(A) <- list(paste0("fila", 1:2), paste0("col", 1:4))
A
##       col1 col2 col3 col4
## fila1   -4   -5    4    5
## fila2   -1    3   -4   -4

La matriz \(A\) tiene \(m = 2\) filas y \(n = 4\) columnas. Su rango máximo posible es \(2\), que es el número de filas.

Una forma común de obtener la SVD es a partir de la matriz \(A^T A\). Esta matriz es cuadrada de tamaño \(n \times n\) (en nuestro caso \(4 \times 4\)), simétrica y semidefinida positiva. Sus valores propios son los cuadrados de los valores singulares de \(A\):

\[ A^T A = V \Sigma^T \Sigma V^T, \]

donde \(\Sigma^T \Sigma\) es una matriz diagonal con los valores \(\sigma_1^2, \sigma_2^2, \dots, \sigma_r^2\) en su diagonal (y ceros en el resto). Por lo tanto, los valores singulares de \(A\) son las raíces cuadradas de los valores propios no nulos de \(A^T A\), y los vectores propios correspondientes forman las columnas de \(V\).

Calculamos \(A^T A\) para nuestra matriz de ejemplo:

AtA <- t(A) %*% A
AtA
##      col1 col2 col3 col4
## col1   17   17  -12  -16
## col2   17   34  -32  -37
## col3  -12  -32   32   36
## col4  -16  -37   36   41

Diagonalización de \(A^T A\)

Como \(A^T A\) es una matriz simétrica real, es diagonalizable mediante una base ortonormal de vectores propios. Esto es, existe una matriz ortogonal \(V\) (cuyas columnas son los vectores propios ortonormales) y una matriz diagonal \(D\) que contiene los valores propios \(\lambda_i\) tales que:

\[ A^T A = V D V^T. \]

Recordemos que \(D = \Sigma^T \Sigma\), por lo que los valores singulares de \(A\) son \(\sigma_i = \sqrt{\lambda_i}\) para \(\lambda_i > 0\). Además, los vectores propios correspondientes a valores propios no nulos forman las primeras \(r\) columnas de \(V\) (los vectores singulares derechos).

Calculamos los valores y vectores propios de \(A^T A\) en R:

# Diagonalización de AtA
eigen_AtA <- eigen(AtA)
valores_propios <- eigen_AtA$values
vectores_propios <- eigen_AtA$vectors

# Mostramos resultados
list(valores_propios = round(valores_propios, 5),
     vectores_propios = round(vectores_propios, 5))
## $valores_propios
## [1] 113.07837  10.92163   0.00000   0.00000
## 
## $vectores_propios
##          [,1]    [,2]     [,3]     [,4]
## [1,] -0.26190 0.91999  0.29158  0.00000
## [2,] -0.54781 0.07729 -0.73590  0.39036
## [3,]  0.52124 0.34201 -0.61093 -0.48795
## [4,]  0.59968 0.17511 -0.01388  0.78072

Construcción de la matriz \(\Sigma\)

La matriz \(\Sigma\) tiene las mismas dimensiones que \(A\) (\(m \times n = 2 \times 4\)) y es diagonal, con los valores singulares \(\sigma_1 \ge \sigma_2 \ge \dots \ge \sigma_r\) en la diagonal principal y ceros en el resto.

En nuestro caso, \(r = 2\), y los valores singulares ya calculados son:

\[ \sigma_1 = \sqrt{\lambda_1}, \quad \sigma_2 = \sqrt{\lambda_2}. \]

Construimos \(\Sigma\) en R:

# Crear matriz de ceros de dimensión 2x4
Sigma <- matrix(0, nrow = 2, ncol = 4)

# Insertar los valores singulares en la diagonal
sigma_vals <- sqrt(valores_propios[valores_propios > 1e-10])
diag(Sigma) <- sigma_vals

# Mostrar Sigma
Sigma
##          [,1]     [,2] [,3] [,4]
## [1,] 10.63383 0.000000    0    0
## [2,]  0.00000 3.304789    0    0

Construcción de la matriz \(U\)

Los vectores singulares izquierdos (columnas de \(U\)) se obtienen a partir de la relación:

\[ U = A V \Sigma^+, \]

donde \(\Sigma^+\) es la pseudoinversa de \(\Sigma\). Como \(\Sigma\) es diagonal de tamaño \(2 \times 4\), su pseudoinversa \(\Sigma^+\) es de tamaño \(4 \times 2\) y tiene en su diagonal los inversos de los valores singulares positivos (y ceros en el resto). Equivalentemente, si tomamos solo las primeras \(r = 2\) columnas de \(V\) (las correspondientes a valores singulares no nulos), denotadas como \(V_r \in \mathbb{R}^{4 \times 2}\), entonces:

\[ U = A \, V_r \, \operatorname{diag}(1/\sigma_1, 1/\sigma_2) \in \mathbb{R}^{2 \times 2}. \]

Además, \(U\) debe ser ortogonal (sus columnas son ortonormales).

Procedemos a calcular \(U\) en R:

# Seleccionar solo los vectores propios correspondientes a valores singulares > 0
r <- length(sigma_vals)  # r = 2
V_r <- vectores_propios[, 1:r]

# Construir la matriz diagonal de inversos
Sigma_inv_diag <- diag(1 / sigma_vals, nrow = r, ncol = r)

# Calcular U
U <- A %*% V_r %*% Sigma_inv_diag

# Redondear para mejor visualización
U <- round(U, 5)
U
##           [,1]     [,2]
## fila1  0.83413 -0.55156
## fila2 -0.55156 -0.83413

Verificación de la factorización SVD

Una vez que tenemos las tres matrices \(U\), \(\Sigma\) y \(V\), debemos comprobar que efectivamente se cumple:

\[ A = U \, \Sigma \, V^T. \]

Realizamos la multiplicación en R y comparamos con la matriz original \(A\):

# Reconstruir A a partir de la SVD
A_reconstruida <- U %*% Sigma %*% t(vectores_propios)

# Redondear para eliminar errores numéricos
A_reconstruida <- round(A_reconstruida, 5)

# Mostrar la matriz reconstruida
A_reconstruida
##           [,1]     [,2]     [,3]     [,4]
## fila1 -3.99998 -4.99998  3.99999  4.99998
## fila2 -1.00000  2.99998 -3.99998 -3.99998
# Comparar con la matriz original A
A
##       col1 col2 col3 col4
## fila1   -4   -5    4    5
## fila2   -1    3   -4   -4