Aplicar SVD con NumPy te permite descomponer cualquier matriz en tres piezas clave para entenderla, reconstruirla y, además, filtrar ruido en sistemas de recomendación. Aquí verás el flujo completo: crear A, obtener U, S y VT, formar Sigma correctamente y usar k para quedarte con los patrones que importan.
¿Cómo aplicar SVD en NumPy para descomponer y reconstruir matrices?
Empezamos en Google Colab importando NumPy y creando una matriz rectangular A de 3x2. Con np.linalg.svd obtenemos las tres transformaciones: U, S (valores singulares) y VT. En NumPy, S regresa como vector, así que formamos una Sigma rectangular para reconstruir A.
¿Qué hace np.linalg.svd y qué devuelve?
Descompone A en U, S y VT.
S contiene los valores singulares de mayor a menor.
VT contiene vectores relacionados con A transpuesta por A; sus columnas corresponden a los eigenvectores de AᵗA.
import numpy as np
A = np.array([[1,2],[3,4],[5,6]])print('shape:', A.shape)U, S, VT = np.linalg.svd(A)print('matriz U:\n', U)print('Sigma (vector S):\n', S)print('V transpuesta (VT):\n', VT)
¿Cómo formar Sigma y reconstruir A?
Creamos Sigma con ceros del mismo shape que A.
Incrustamos np.diag(S) en la esquina superior izquierda de Sigma.
Reconstruimos con el orden: U @ Sigma @ VT.
Interpretación: rotación, escalado y cambio de dimensión, luego rotación de salida.
¿Cómo filtrar ruido con SVD en un sistema de recomendación?
Modelamos 4 usuarios x 3 películas: Dune (ciencia ficción), Shrek (comedia) y Los Cazafantasmas (híbrida). Definimos dos patrones de gustos: uno de ciencia ficción y otro de comedia. Construimos una matriz señal de rango 2 combinando estos patrones y luego añadimos ruido para simular inconsistencias reales. Con SVD de la matriz ruidosa, los valores singulares revelan cuántos patrones dominan.
¿Cómo se construye la señal y el ruido?
Patrón sci-fi alto en Dune, bajo en Shrek, medio-alto en la híbrida.
Patrón comedia bajo en Dune, alto en Shrek, medio en la híbrida.
Señal: usuarios puros y combinaciones lineales de ambos patrones.
Ruido: matriz aleatoria con np.random.randn escalada por 0.3.
¿Qué aprendizajes y habilidades clave obtienes con SVD?
SVD no solo descompone: también diagnostica patrones, filtra ruido y permite compresión eficiente. En matrices grandes, como las de plataformas con millones de usuarios y películas, se observan los valores singulares y suelen conservarse solo los principales (por ejemplo, 50 o 100) para capturar patrones de gusto latentes.
SVD: descomposición en U, Sigma y VT para entender transformaciones básicas.
Valores singulares: orden de importancia de patrones en los datos.
Sigma rectangular: construcción desde el vector S con np.diag y slicing.
Reconstrucción: U @ Sigma @ VT y lectura geométrica de las transformaciones.
Selección de k: conservar lo esencial y tratar lo pequeño como ruido.
Filtrado de ruido: mejora la señal de calificaciones y la estabilidad de recomendaciones.
Compresión: almacenar pocos patrones en lugar de matrices gigantes.
Interpretación de U y VT: U relaciona usuarios con patrones; VT relaciona películas con patrones; recomendación por similitud de perfiles.
Ponlo en práctica: vuelve al proyecto y reconstruye con k = 1. ¿Qué tan bien captura las preferencias originales de los usuarios? Comparte tu matriz y tu análisis en los comentarios.
### Filtrar Ruido con SVD en un Sistema de Recomendaciónimport numpy as np
#### Patrones de Scifi y Comediapatron_Scifi=np.array([5,1,4])patron_Comedia=np.array([1,5,3])#### Matriz AsignalA_signal=np.array([patron_Scifi, patron_Comedia, patron_Scifi*0.5+patron_Comedia*0.5, patron_Scifi*0.8+patron_Comedia*0.2])print(f"Matriz A signal: {A_signal}")Matriz A signal:[[5.1.4.][1.5.3.][3.3.3.5][4.21.83.8]]print(f"Matriz A signal shape: {A_signal.shape}")Matriz A signal shape:(4,3)#### Señal de Ruido y Señal Realnp.random.seed(42)ruido=np.random.randn(*A_signal.shape)*0.3print(f"Ruido: {ruido}")Ruido:[[0.14901425-0.041479290.19430656][0.45690896-0.07024601-0.07024109][0.473763840.23023042-0.14084232][0.16276801-0.13902531-0.13971893]]señal_real=A_signal+ruido
print(f"Señal real (A_signal + ruido): {señal_real}")Señal real (A_signal + ruido):[[5.149014250.958520714.19430656][1.456908964.929753992.92975891][3.473763843.230230423.35915768][4.362768011.660974693.66028107]]#### Descomposición SVD de la Señal RealU, S, VT = np.linalg.svd(señal_real)print(f'Vector de valores singulares: {S}')#### Filtración de Ruido con SVD con k=1k=1Sigma_k = np.diag(S[:k])Sigma=np.diag(S)print(f'Matriz Sigma_k con los {k} valores singulares más grandes: {Sigma_k}')Matriz Sigma_k con los 1 valores singulares más grandes:[[11.49314153]]print(f'Matriz Sigma completa: {Sigma}')Matriz Sigma completa:[[11.493141530.0.][0.4.103549190.][0.0.0.27576758]]U_k=U[:,:k]VT_k=VT[:k,:]print(f'Matriz U_k: {U_k}')Matriz U_k:[[-0.55286005][-0.4308512][-0.50160466][-0.50705599]]print(f'Matriz VT_k: {VT_k}')Matriz VT_k:[[-0.64638715-0.44517193-0.61968185]]A_filtrada = U_k @ Sigma_k @ VT_k
print(f'Matriz A Signal: {A_signal}')Matriz A Signal:[[5.1.4.][1.5.3.][3.3.3.5][4.21.83.8]]print(f'Matriz A filtrada: {np.round(A_filtrada, decimals=2)}')Matriz A filtrada:[[4.112.833.94][3.22.23.07][3.732.573.57][3.772.593.61]]varianza_explicada_k = np.sum(S[:k]**2)/ np.sum(S**2)print(f'Varianza explicada por los {k} primeros componentes: {varianza_explicada_k:.2f}')Varianza explicada por los 1 primeros componentes:0.89
P.D.: Al momento de crear la señal de ruido es necesario según mi opinion colocar la semilla :(np.random.seed(42))