El ACP calcula los vectores propios de la matriz de covarianza ("ejes principales") y los ordena por sus valores propios (cantidad de varianza explicada). Los datos centrados pueden entonces proyectarse sobre estos ejes principales para obtener componentes principales ("puntuaciones"). Para reducir la dimensionalidad, se puede conservar sólo un subconjunto de componentes principales y descartar el resto. (Vea aquí una introducción al PCA para profanos .)
Dejemos que $\mathbf X_\text{raw}$ sea el $n\times p$ matriz de datos con $n$ filas (puntos de datos) y $p$ columnas (variables, o características). Después de restar el vector medio $\boldsymbol \mu$ de cada fila, obtenemos el centrado matriz de datos $\mathbf X$ . Sea $\mathbf V$ sea el $p\times k$ matriz de algún $k$ eigenvectores que queremos utilizar; estos serían la mayoría de las veces los $k$ vectores propios con los mayores valores propios. Entonces el $n\times k$ matriz de proyecciones PCA ("puntuaciones") vendrá dada simplemente por $\mathbf Z=\mathbf {XV}$ .
Esto se ilustra en la figura siguiente: el primer subgrupo muestra algunos datos centrados (los mismos datos que utilizo en mis animaciones en el hilo enlazado) y sus proyecciones sobre el primer eje principal. El segundo subgrupo muestra sólo los valores de esta proyección; la dimensionalidad se ha reducido de dos a una:
Para poder reconstruir las dos variables originales a partir de este componente principal, podemos volver a asignarlo a $p$ dimensiones con $\mathbf V^\top$ . En efecto, los valores de cada PC deben colocarse en el mismo vector que se utilizó para la proyección; compárense los subplots 1 y 3. El resultado viene dado entonces por $\hat{\mathbf X} = \mathbf{ZV}^\top = \mathbf{XVV}^\top$ . Lo estoy mostrando en la tercera subtrama de arriba. Para obtener la reconstrucción final $\hat{\mathbf X}_\text{raw}$ necesitamos añadir el vector medio $\boldsymbol \mu$ a eso:
$$\boxed{\text{PCA reconstruction} = \text{PC scores} \cdot \text{Eigenvectors}^\top + \text{Mean}}$$
Obsérvese que se puede pasar directamente de la primera subparcela a la tercera multiplicando $\mathbf X$ con el $\mathbf {VV}^\top$ matriz; se denomina proyección matriz. Si todos los $p$ se utilizan los vectores propios, entonces $\mathbf {VV}^\top$ es la matriz de identidad (no se realiza ninguna reducción de la dimensionalidad, por lo que la "reconstrucción" es perfecta). Si sólo se utiliza un subconjunto de vectores propios, no es la identidad.
Esto funciona para un punto arbitrario $\mathbf z$ en el espacio del PC; se puede asignar al espacio original mediante $\hat{\mathbf x} = \mathbf{zV}^\top$ .
Descartar (eliminar) los ordenadores principales
A veces se quiere descartar (eliminar) uno o pocos de los PCs principales y mantener el resto, en lugar de mantener los PCs principales y descartar el resto (como en el caso anterior). En este caso, todas las fórmulas se mantienen exactamente lo mismo pero $\mathbf V$ debe consistir en todos los ejes principales excepto para los que uno quiere descartar. En otras palabras, $\mathbf V$ debe incluir siempre todos los PC que uno quiera conservar.
Advertencia sobre el ACP en la correlación
Cuando se hace el PCA en la matriz de correlación (y no en la matriz de covarianza), los datos brutos $\mathbf X_\mathrm{raw}$ no sólo se centra restando $\boldsymbol \mu$ pero también escalado dividiendo cada columna por su desviación estándar $\sigma_i$ . En este caso, para reconstruir los datos originales, hay que reescalar las columnas de $\hat{\mathbf X}$ con $\sigma_i$ y sólo entonces volver a añadir el vector medio $\boldsymbol \mu$ .
Ejemplo de procesamiento de imágenes
Este tema surge a menudo en el contexto del procesamiento de imágenes. Considere Lenna -- una de las imágenes estándar en la literatura de procesamiento de imágenes (siga los enlaces para encontrar su procedencia). Abajo, a la izquierda, muestro la variante en escala de grises de esta $512\times 512$ imagen (archivo disponible aquí ).
Podemos tratar esta imagen en escala de grises como una $512\times 512$ matriz de datos $\mathbf X_\text{raw}$ . Realizo el PCA en él y calculo $\hat {\mathbf X}_\text{raw}$ utilizando los primeros 50 componentes principales. El resultado se muestra a la derecha.
Revertir la SVD
El PCA está muy relacionado con la descomposición del valor singular (SVD), véase Relación entre SVD y PCA. Cómo utilizar la SVD para realizar el PCA? para más detalles. Si un $n\times p$ matriz $\mathbf X$ se convierte en SVD como $\mathbf X = \mathbf {USV}^\top$ y se selecciona un $k$ -vector de dimensiones $\mathbf z$ que representa el punto en el "reducido" $U$ -espacio de $k$ dimensiones, para luego volver a asignarlas a $p$ dimensiones hay que multiplicarlo por $\mathbf S^\phantom\top_{1:k,1:k}\mathbf V^\top_{:,1:k}$ .
Ejemplos en R, Matlab, Python y Stata
Llevaré a cabo el PCA en el Datos de Fisher Iris y luego reconstruirlo utilizando los dos primeros componentes principales. Estoy haciendo PCA en la matriz de covarianza, no en la matriz de correlación, es decir, no estoy escalando las variables aquí. Pero todavía tengo que añadir la media de nuevo. Algunos paquetes, como Stata, se encargan de ello mediante la sintaxis estándar. Gracias a @StasK y @Kodiologist por su ayuda con el código.
Comprobaremos la reconstrucción del primer punto de datos, que es:
5.1 3.5 1.4 0.2
Matlab
load fisheriris
X = meas;
mu = mean(X);
[eigenvectors, scores] = pca(X);
nComp = 2;
Xhat = scores(:,1:nComp) * eigenvectors(:,1:nComp)';
Xhat = bsxfun(@plus, Xhat, mu);
Xhat(1,:)
La salida:
5.083 3.5174 1.4032 0.21353
R
X = iris[,1:4]
mu = colMeans(X)
Xpca = prcomp(X)
nComp = 2
Xhat = Xpca$x[,1:nComp] %*% t(Xpca$rotation[,1:nComp])
Xhat = scale(Xhat, center = -mu, scale = FALSE)
Xhat[1,]
La salida:
Sepal.Length Sepal.Width Petal.Length Petal.Width
5.0830390 3.5174139 1.4032137 0.2135317
Para un ejemplo en R de reconstrucción PCA de imágenes, véase también esta respuesta .
Python
import numpy as np
import sklearn.datasets, sklearn.decomposition
X = sklearn.datasets.load_iris().data
mu = np.mean(X, axis=0)
pca = sklearn.decomposition.PCA()
pca.fit(X)
nComp = 2
Xhat = np.dot(pca.transform(X)[:,:nComp], pca.components_[:nComp,:])
Xhat += mu
print(Xhat[0,])
La salida:
[ 5.08718247 3.51315614 1.4020428 0.21105556]
Tenga en cuenta que esto difiere ligeramente de los resultados en otros idiomas. Esto se debe a que la versión de Python del conjunto de datos Iris contiene errores .
Stata
webuse iris, clear
pca sep* pet*, components(2) covariance
predict _seplen _sepwid _petlen _petwid, fit
list in 1
iris seplen sepwid petlen petwid _seplen _sepwid _petlen _petwid
setosa 5.1 3.5 1.4 0.2 5.083039 3.517414 1.403214 .2135317
11 votos
Pongo este hilo de preguntas y respuestas, porque estoy cansado de ver decenas de preguntas preguntando esto mismo y no poder cerrarlas como duplicadas porque no tenemos un hilo canónico sobre este tema. Hay varios hilos similares con respuestas decentes pero todos parecen tener serias limitaciones, como por ejemplo centrarse exclusivamente en R.
4 votos
Aprecio el esfuerzo - creo que hay una gran necesidad de reunir información sobre PCA, lo que hace, lo que no hace, en uno o varios hilos de alta calidad. Me alegro de que te hayas encargado de hacerlo.
3 votos
No estoy convencido de que esta respuesta canónica de "limpieza" sirva para su propósito. Lo que tenemos aquí es un excelente, genérico pregunta y respuesta, pero cada una de las preguntas tenía algunas sutilezas sobre el PCA en la práctica que se pierden aquí. Esencialmente, usted ha tomado todas las preguntas, ha hecho PCA en ellas y ha descartado los componentes principales inferiores, donde a veces se esconden detalles ricos e importantes. Además, has recurrido a la notación de álgebra lineal de los libros de texto, que es precisamente lo que hace que el ACP sea opaco para mucha gente, en lugar de utilizar la lengua franca de los estadísticos ocasionales, que es R.
2 votos
@Thomas Gracias. Creo que tenemos un desacuerdo, encantado de discutirlo en el chat o en Meta. Muy brevemente: (1) En efecto, podría ser mejor responder a cada pregunta individualmente, pero la cruda realidad es que eso no sucede. Muchas preguntas se quedan sin respuesta, como probablemente la tuya. (2) La comunidad prefiere las respuestas genéricas que son útiles para mucha gente; puedes ver qué tipo de respuestas son las más votadas. (3) Estoy de acuerdo con lo de las matemáticas, ¡pero por eso di el código R aquí! (4) No estoy de acuerdo con la lengua franca; personalmente, no conozco R.
0 votos
@ThomasBrowne Pues sólo tienes que pinchar en el enlace que he puesto arriba: chat.stackexchange.com/rooms/18/ten-fold -- y te lleva al chat. A estas alturas la conversación sobre tu comentario ha quedado un poco atrás, así que aquí tienes un enlace al historial de chat correspondiente: chat.stackexchange.com/transcript/message/31659626#31659626