Cómo implementar PCA desde cero con NumPy
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)
Cómo implementar PCA desde cero con NumPy
Resumen
Implementar PCA desde cero con NumPy te permite entender qué ocurre detrás de funciones como fit_transform de Scikit-learn. Aquí aprendes a construir el algoritmo en cuatro pasos, validarlo contra la librería y visualizar la reducción de dimensiones, ideal si vienes de fundamentos de álgebra lineal y quieres dar el salto a machine learning aplicado.
Qué pasos componen el algoritmo de PCA
El Principal Component Analysis se construye encadenando operaciones que ya conoces de NumPy. Son cuatro pasos que conectan estadística descriptiva, álgebra lineal y proyección vectorial.
- Estandarizar los datos para que tengan media cero y escala comparable.
- Calcular la matriz de covarianza que describe forma y orientación.
- Aplicar eigenanalysis para encontrar los ejes de máxima varianza.
- Proyectar los datos originales sobre los nuevos ejes con un producto matricial.
¿Qué es PCA en una frase? Es una técnica que reduce la dimensión de tus datos proyectándolos sobre los ejes donde la varianza es máxima, conservando la mayor cantidad de información posible. [00:14]
Cómo estandarizar los datos antes de aplicar PCA
Primero centras la matriz restando la media por columna y luego divides por la desviación estándar. Ese paso garantiza que ninguna característica domine por tener una escala mayor.
python x_centrado = X - np.mean(X, axis=0) x_estandarizado = x_centrado / np.std(X, axis=0)
El parámetro axis=0 es clave porque calculas media y desviación por columnas, que es donde viven las características. La desviación estándar te dice qué tan dispersos están los puntos respecto a la media. [02:30]
Cómo calcular la matriz de covarianza y los eigenvectores
La matriz de covarianza describe cómo varían juntas las características. En NumPy se calcula con np.cov, pero hay un detalle importante con la orientación de los datos.
python matriz_cov = np.cov(x_estandarizado, rowvar=False)
Usas rowvar=False porque tus columnas son las características, no las filas. Si lo dejas en su valor por defecto, NumPy interpreta las filas como variables y obtienes una matriz incorrecta. [03:45]
Cómo ordenar eigenvalues y eigenvectores de mayor a menor
Una vez tienes la matriz de covarianza, aplicas np.linalg.eig para obtener eigenvalues y eigenvectores. Pero NumPy no garantiza que vengan ordenados, así que necesitas ordenarlos manualmente.
python eigenvalues, eigenvectores = np.linalg.eig(matriz_cov) indices_ordenados = np.argsort(eigenvalues)[::-1] eigenvectores_ordenados = eigenvectores[:, indices_ordenados]
El truco [::-1] invierte el array para que el orden sea de mayor a menor varianza. Así te aseguras de que la primera columna corresponde al componente principal que captura más información. [04:50]
¿Por qué hay que ordenar los eigenvectores? Porque cada uno representa un eje de varianza, y solo conservando los de mayor eigenvalue obtienes la mejor reducción dimensional posible.
Cómo proyectar los datos sobre los componentes principales
El último paso es seleccionar los primeros n_componentes eigenvectores y multiplicarlos por la matriz estandarizada. Ese producto punto es la proyección final.
python componentes_principales = eigenvectores_ordenados[:, :n_componentes] x_proyectado = x_estandarizado @ componentes_principales return x_proyectado
Con esto cierras la función pca_desde_0(X, n_componentes). El slicing [:, :n_componentes] te da exactamente los K ejes que quieres conservar. [06:20]
Cómo validar tu PCA contra el de Scikit-learn
Para comparar resultados, importa PCA y StandardScaler de Scikit-learn. La trampa común es olvidar estandarizar antes de pasar los datos a la librería, lo que produce resultados diferentes.
python from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA
scaler = StandardScaler() datos_escalados_sklearn = scaler.fit_transform(datos_3D)
pca_sklearn = PCA(n_components=2) datos_pca_sklearn = pca_sklearn.fit_transform(datos_escalados_sklearn)
Al imprimir las primeras cinco filas redondeadas a dos decimales con np.round, deberías ver valores prácticamente idénticos a los de tu implementación. [08:40]
Por qué los signos pueden cambiar entre ambos PCA
Es posible que tu PCA y el de Scikit-learn devuelvan los mismos números pero con signos opuestos. No es un error: es comportamiento esperado.
Un eigenvector define una dirección en el espacio, no un sentido. Los vectores (1, 1) y (-1, -1) describen exactamente la misma línea, solo que apuntan en sentidos contrarios. Ambos son válidos como ejes principales. [11:15]
- Mismo eje, sentidos opuestos.
- Magnitudes idénticas.
- Resultado geométricamente equivalente.
Cómo visualizar la reducción de 3D a 2D con Matplotlib
Una gráfica lado a lado confirma que tu algoritmo funciona. Crea dos subplots con plt.subplots(1, 2, figsize=(14, 6)) y dibuja los puntos proyectados de cada versión.
python fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6)) ax1.scatter(datos_pca_nuestro[:, 0], datos_pca_nuestro[:, 1], alpha=0.7) ax1.set_title('Nuestro PCA') ax2.scatter(datos_pca_sklearn[:, 0], datos_pca_sklearn[:, 1], alpha=0.7) ax2.set_title('PCA de Scikit-learn') plt.suptitle('Validación de nuestro PCA vs Sklearn') plt.show()
Los nueve puntos del pancake tridimensional ahora viven en un plano. Pasaste de un cubo a una proyección 2D que conserva la estructura esencial de los datos. [12:30]
Como ejercicio, crea una matriz con más de tres dimensiones, aplica tu PCA y el de la librería, y reduce a las dimensiones que quieras. Comparte tus resultados en los comentarios y cuéntanos si te encontraste con el detalle de los signos invertidos.