Capítulo 5

PCA: Principal Component Analysis

5.1 ¿Qué es PCA?

PCA encuentra las direcciones de máxima varianza en los datos. Es la herramienta fundamental de reducción de dimensionalidad.

Reducción

Proyectar datos de d dimensiones a k < d, perdiendo la menor información posible.

Visualización

Datos de alta dimensión → 2D o 3D con PCA.

Preprocesamiento

Reducir ruido, eliminar multicolinealidad, acelerar modelos.

5.2 La Matemática

PCA maximiza la varianza del dato proyectado:

maxu=1Var(uX)=maxu=1uΣu\max_{\|\mathbf{u}\|=1} \text{Var}(\mathbf{u}^\top \mathbf{X}) = \max_{\|\mathbf{u}\|=1} \mathbf{u}^\top \Sigma \mathbf{u}

Esto es el Rayleigh quotient: la solución son los eigenvectores de Σ. El primer PC es el eigenvector con mayor eigenvalor.

Equivalentemente, PCA se resuelve con SVD de la matriz centrada:

X=UΣVX = U \Sigma V^\top

Las columnas de V son los componentes principales. Las proyecciones son XV=UΣXV = U\Sigma (scores).

5.3 Varianza Explicada

Cada componente explica una proporción de la varianza total:

varianza explicadak=σk2j=1dσj2\text{varianza explicada}_k = \frac{\sigma_k^2}{\sum_{j=1}^d \sigma_j^2}

El scree plot muestra la varianza por componente — busca el "codo" para elegir k.

python
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.datasets import load_digits

digits = load_digits()
X = digits.data  # 1797 × 64
print(f"Datos: {X.shape}")

pca = PCA()
pca.fit(X)

varianza = pca.explained_variance_ratio_
acumulada = np.cumsum(varianza)

# Scree plot
plt.plot(range(1, len(varianza)+1), varianza, 'o-')
plt.xlabel('Componente')
plt.ylabel('Varianza explicada')
plt.show()

# Cuántos componentes para 90%?
k = np.argmax(acumulada >= 0.90) + 1
print(f"Componentes para 90%: {k}")

5.4 Visualización Interactiva

Datos 2D → PCA encuentra el primer componente (máxima varianza). Arrastra los puntos para ver cómo cambia.

Arrastra puntos para ver cómo cambia PCA
Varianza explicada PC1: 90.9%PC2: 9.1%

5.5 PCA para Compresión

python
from sklearn.datasets import fetch_olivetti_faces
from sklearn.decomposition import PCA

# faces = fetch_olivetti_faces()
# X = faces.data  # 400 × 4096

# Comprimir a 50 componentes
# pca = PCA(50)
# X_compressed = pca.fit_transform(X)
# X_reconstructed = pca.inverse_transform(X_compressed)

# Tasa de compresión
# original = 4096
# comprimido = 50 + 50 * 4096 / 400  # componentes + eigenfaces
# print(f"Compresión: {original / comprimido:.1f}x")

Cada componente principal ("eigenface") es una dirección de variación en el espacio de imágenes.

5.6 PCA desde Cero (vía SVD)

python
import numpy as np

def pca_svd(X, k):
    """PCA usando SVD (más estable numéricamente que eigendecomposition)"""
    X_centered = X - X.mean(axis=0)
    U, S, Vt = np.linalg.svd(X_centered, full_matrices=False)
    components = Vt[:k]  # k × d
    scores = U[:, :k] * S[:k]  # n × k
    varianza = S**2 / (S**2).sum()
    return components, scores, varianza[:k]

X = np.random.randn(100, 10)
components, scores, var = pca_svd(X, 3)
print(f"Componentes: {components.shape}")
print(f"Scores: {scores.shape}")
print(f"Varianza: {var}")

5.7 PCA vs t-SNE vs UMAP

PCA

Lineal, determinista, rápido, preserva distancias globales.

t-SNE

No lineal, preserva vecindades locales, lento, estocástico.

UMAP

No lineal, balance local-global, más rápido que t-SNE.

PCA es el punto de partida. Si no alcanza, prueba t-SNE o UMAP para visualización.