Matriz de covarianza y eigenvectores en Python
Clase 4 de 12 • Curso Avanzado de Álgebra Lineal y Machine Learning: PCA y SVD
Contenido del curso
Eigen-Análisis
Reducción de Dimensionalidad con PCA
Descomposición en Valores Singulares (SVD)
Comprende cómo la matriz de covarianza revela la forma de tus datos en machine learning y cómo los eigenvectores y eigenvalores te muestran las direcciones de máxima información. Con ejemplos claros y código en Google Colab usando NumPy y Matplotlib, verás cómo pasar de la intuición a la implementación y preparar el terreno para la reducción de dimensionalidad con PCA.
¿Qué es la matriz de covarianza y por qué importa en machine learning?
La matriz de covarianza es un resumen estadístico clave: es cuadrada y cuenta cómo se comportan tus características. En la diagonal principal están las varianzas (dispersión por característica). Fuera de la diagonal están las covarianzas (relación lineal entre pares de características).
- Varianza alta: mucha dispersión respecto al promedio.
- Covarianza positiva: cuando una característica crece, la otra también; la nube forma una elipse que sube a la derecha.
- Covarianza negativa: si una sube, la otra baja; la elipse desciende a la derecha.
- Covarianza cercana a 0: no hay relación lineal clara; nube casi circular.
Analizar esta matriz permite detectar redundancia y ubicar las direcciones de máxima información, base del PCA.
¿Cómo interpretar varianza y covarianza?
- La diagonal indica dispersión por eje. Valores más grandes implican escalas más amplias.
- Los términos fuera de la diagonal muestran la tendencia conjunta: positiva, negativa o nula.
- La forma elíptica en 2D refleja magnitud y signo de la covarianza.
¿Por qué centrar datos antes de graficar?
- Restar la media por columna (centrado) alinea la nube con el origen.
- Facilita comparar direcciones y longitudes de vectores en el plano.
- Evita sesgos visuales al trazar flechas y ejes principales.
¿Cómo se calculan eigenvalores y eigenvectores y qué revelan?
Con la matriz de covarianza, obtienes eigenvalores y eigenvectores. Ordenarlos de mayor a menor con argsort te permite identificar el eje principal. La raíz cuadrada del eigenvalor da la desviación estándar sobre ese eje, útil para escalar la flecha en el gráfico con quiver.
- El eigenvector principal (flecha verde) sigue la dirección de máxima varianza. Captura la mayor parte de la información.
- El segundo eigenvector (flecha roja) captura el ruido restante en 2D.
- Si no hay relación entre variables, los eigenvectores quedan alineados a los ejes x e y.
Escenarios mostrados con datos sintéticos:
- Covarianza positiva (horas de estudio vs. calificación): elipse que asciende a la derecha; el eje principal sigue esa pendiente.
- Covarianza negativa (horas de videojuegos vs. calificación): elipse que desciende a la derecha; el eje principal sigue la caída.
- Sin covarianza (aleatorios): nube ancha y baja; ejes principales alineados a x e y.
Esto conecta directo con PCA: si el primer eigenvalor es mucho mayor que el segundo, puedes proyectar los datos sobre el eje principal y reducir de 2D a 1D conservando casi toda la información.
¿Cómo replicar el análisis con NumPy y Matplotlib paso a paso?
A continuación, el flujo reproducido con NumPy y Matplotlib: cálculo de covarianza, descomposición espectral, ordenamiento, centrado y gráficos con scatter plot y quiver.
import numpy as np import matplotlib.pyplot as plt # Función de análisis y gráfico def analizar_graficar(ax, datos, titulo, feature_names): # 1) Matriz de covarianza por columnas cov = np.cov(datos, rowvar=False) # 2) Eigenvalores (w) y eigenvectores (V) w, V = np.linalg.eig(cov) # 3) Ordenar de mayor a menor idx = np.argsort(w)[::-1] w = w[idx] V = V[:, idx] # 4) Centrado de datos (por columnas) datos_centrados = datos - np.mean(datos, axis=0) # 5) Dispersión de los datos ax.scatter(datos_centrados[:, 0], datos_centrados[:, 1], alpha=0.7) # 6) Flechas de eigenvectores escaladas por la desviación estándar for i in range(len(w)): length = np.sqrt(w[i]) # desviación estándar sobre ese eje ax.quiver(0, 0, V[0, i] * length, V[1, i] * length, angles='xy', scale_units='xy', scale=1, color=f'C{i+2}', width=0.015, label=f'eje {i+1} (eigenvalor={w[i]:.1f})') # 7) Estética ax.set_title(titulo) ax.set_xlabel(f'{feature_names[0]}') ax.set_ylabel(f'{feature_names[1]}') ax.grid(True) ax.legend() return cov # Datos de ejemplo # Covarianza positiva: horas de estudio vs. calificación datos_pos = np.array([ [2, 65], [3, 70], [5, 75], [6, 85], [8, 88], [9, 94] ]) # Covarianza negativa: horas de videojuegos vs. calificación datos_neg = np.array([ [10, 60], [8, 70], [7, 72], [5, 85], [3, 90], [1, 95] ]) # Sin covarianza: datos aleatorios controlados por semilla np.random.seed(42) datos_cero = np.random.randn(100, 2) * np.array([10.0, 5.0]) # Gráficos fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(21, 7)) cov_pos = analizar_graficar( ax1, datos_pos, 'Covarianza positiva', ['horas de estudio', 'calificación'] ) cov_neg = analizar_graficar( ax2, datos_neg, 'Covarianza negativa', ['horas de videojuegos', 'calificación'] ) cov_cero = analizar_graficar( ax3, datos_cero, 'Sin covarianza', ['característica 1', 'característica 2'] ) plt.show() print('Covarianza positiva:\n', cov_pos) print('\nCovarianza negativa:\n', cov_neg) print('\nSin covarianza:\n', cov_cero)
Te invito a comentar: si tus dos características fueran años de experiencia y salario (con fuerte covarianza positiva) y la varianza del salario fuera mucho mayor, ¿la elipse de datos sería más vertical u horizontal? ¿hacia dónde apuntaría el eigenvector principal? Comparte tu análisis y resultados.