Estoy trabajando en R a través de un excelente tutorial de PCA de Lindsay I Smith y me estoy atascando en la última etapa. La secuencia de comandos R a continuación nos lleva a la etapa (en la p.19) donde los datos originales se están reconstruyendo a partir del Componente Principal (singular en este caso), que debería generar una gráfica de línea recta a lo largo del eje PCA1 (dado que los datos solo tiene 2 dimensiones, la segunda de las cuales se ha eliminado intencionalmente).
d = data.frame(x=c(2.5,0.5,2.2,1.9,3.1,2.3,2.0,1.0,1.5,1.1),
y=c(2.4,0.7,2.9,2.2,3.0,2.7,1.6,1.1,1.6,0.9))
# mean-adjusted values
d$x_adj = d$x - mean(d$x)
d$y_adj = d$y - mean(d$y)
# calculate covariance matrix and eigenvectors/values
(cm = cov(d[,1:2]))
#### outputs #############
# x y
# x 0.6165556 0.6154444
# y 0.6154444 0.7165556
##########################
(e = eigen(cm))
##### outputs ##############
# $values
# [1] 1.2840277 0.0490834
#
# $vectors
# [,1] [,2]
# [1,] 0.6778734 -0.7351787
# [2,] 0.7351787 0.6778734
###########################
# principal component vector slopes
s1 = e$vectors[1,1] / e$vectors[2,1] # PC1
s2 = e$vectors[1,2] / e$vectors[2,2] # PC2
plot(d$x_adj, d$y_adj, asp=T, pch=16, xlab='x', ylab='y')
abline(a=0, b=s1, col='red')
abline(a=0, b=s2)
# PCA data = rowFeatureVector (transposed eigenvectors) * RowDataAdjust (mean adjusted, also transposed)
feat_vec = t(e$vectors)
row_data_adj = t(d[,3:4])
final_data = data.frame(t(feat_vec %*% row_data_adj)) # ?matmult for details
names(final_data) = c('x','y')
#### outputs ###############
# final_data
# x y
# 1 0.82797019 -0.17511531
# 2 -1.77758033 0.14285723
# 3 0.99219749 0.38437499
# 4 0.27421042 0.13041721
# 5 1.67580142 -0.20949846
# 6 0.91294910 0.17528244
# 7 -0.09910944 -0.34982470
# 8 -1.14457216 0.04641726
# 9 -0.43804614 0.01776463
# 10 -1.22382056 -0.16267529
############################
# final_data[[1]] = -final_data[[1]] # for some reason the x-axis data is negative the tutorial's result
plot(final_data, asp=T, xlab='PCA 1', ylab='PCA 2', pch=16)
Esto es lo más lejos que tengo, y todo está bien hasta ahora. Pero no puedo entender cómo se obtienen los datos para la trama final, la varianza atribuible a PCA 1, que Smith traza como:
Esto es lo que he intentado (que ignora agregar los medios originales):
trans_data = final_data
trans_data[,2] = 0
row_orig_data = t(t(feat_vec[1,]) %*% t(trans_data))
plot(row_orig_data, asp=T, pch=16)
.. y obtuve un error:
.. porque he perdido una dimensión de datos de alguna manera en la multiplicación de matrices. Estaría muy agradecido por una idea de lo que está mal aquí.
* Editar *
Me pregunto si esta es la fórmula correcta:
row_orig_data = t(t(feat_vec) %*% t(trans_data))
plot(row_orig_data, asp=T, pch=16, cex=.5)
abline(a=0, b=s1, col='red')
Pero estoy un poco confundido si es así porque (a) entiendo que las rowVectorFeature
necesidades deben reducirse a la dimensionalidad deseada (el vector propio para PCA1), y (b) no se alinea con la abline de PCA1:
Cualquier opinión muy apreciada.
s1
Respuestas:
Estuviste muy cerca de allí y te atrapó un problema sutil al trabajar con matrices en R. Trabajé de tu parte
final_data
y obtuve los resultados correctos de forma independiente. Luego eché un vistazo más de cerca a tu código. Para resumir una larga historia, donde escribistehubieras estado bien si hubieras escrito
trans_data
t(feat_vec[1,])
row_orig_data = t(as.matrix(feat_vec[1,],ncol=1,nrow=2) %*% t(trans_data))
non-conformable arguments
final_data
row_orig_data
t(t(p) %*% t(q)) = q %*% t
Escribir
entonces para recuperar sus datos en su base original necesita
Puede poner a cero las partes de sus datos que se proyectan a lo largo del segundo componente utilizando
y luego puedes transformarte como antes
Al trazar estos en el mismo diagrama, junto con la línea del componente principal en verde, se muestra cómo funciona la aproximación.
Retrocedamos a lo que tenías. Esta linea estaba bien
feat_vec %*% row_data_adj
Entonces tuviste
Esto está bien: solo está poniendo a cero las partes de sus datos que se proyectan a lo largo del segundo componente. Donde va mal es
t(feat_vec[1,]) %*% t(trans_data)
fuente
Creo que tiene la idea correcta, pero tropezó con una característica desagradable de R. Aquí nuevamente el código relevante como lo ha dicho:
Básicamente
final_data
contiene las coordenadas de los puntos originales con respecto al sistema de coordenadas definido por los vectores propios de la matriz de covarianza. Para reconstruir los puntos originales, se debe multiplicar cada vector propio con la coordenada transformada asociada, p. Ej.que produciría las coordenadas originales del primer punto. En su pregunta se establece el segundo componente correctamente a cero,
trans_data[,2] = 0
. Si luego (como ya editó) calculaUsted calcula la fórmula (1) para todos los puntos simultáneamente. Tu primer acercamiento
calcula algo diferente y solo funciona porque R elimina automáticamente el atributo de dimensión
feat_vec[1,]
, por lo que ya no es un vector de fila, sino que se trata como un vector de columna. La transposición posterior lo convierte en un vector de fila nuevamente y esa es la razón por la cual al menos el cálculo no produce un error, pero si revisa las matemáticas verá que es algo diferente a (1). En general, es una buena idea en las multiplicaciones de matrices suprimir la caída del atributo de dimensión que puede lograrse mediante eldrop
parámetro, por ejemplofeat_vec[1,,drop=FALSE]
.fuente
drop=F
argumento.Después de explorar este ejercicio, puede probar las formas más fáciles en R. Hay dos funciones populares para hacer PCA:
princomp
yprcomp
. Laprincomp
función realiza la descomposición del valor propio como lo hizo en su ejercicio. Laprcomp
función utiliza la descomposición de valores singulares. Ambos métodos darán los mismos resultados casi todo el tiempo: esta respuesta explica las diferencias en R, mientras que esta respuesta explica las matemáticas . (Gracias a TooTone por los comentarios ahora integrados en esta publicación).Aquí usamos ambos para reproducir el ejercicio en R. Primero usando
princomp
:Segundo uso
prcomp
:Claramente, los signos están invertidos, pero la explicación de la variación es equivalente.
fuente