Visualización de PCA en R: puntos de datos, vectores propios, proyecciones, elipse de confianza

8

Tengo un conjunto de datos de 17 personas, clasificando 77 declaraciones. Quiero extraer componentes principales en una matriz de correlación transpuesta de correlaciones entre personas (como variables) a través de declaraciones (como casos). Yo sé, es raro, se llama Metodología Q .

Quiero ilustrar cómo funciona PCA en este contexto, extrayendo y visualizando valores / vectores propios para solo un par de datos. (Debido a que pocas personas en mi disciplina obtienen PCA, y mucho menos su aplicación a Q, incluido yo mismo).

Quiero la visualización de este fantástico tutorial , solo para mis datos reales .

Gran visualización

Deje que esto sea un subconjunto de mis datos:

Person1 <- c(-3,1,1,-3,0,-1,-1,0,-1,-1,3,4,5,-2,1,2,-2,-1,1,-2,1,-3,4,-6,1,-3,-4,3,3,-5,0,3,0,-3,1,-2,-1,0,-3,3,-4,-4,-7,-5,-2,-2,-1,1,1,2,0,0,2,-2,4,2,1,2,2,7,0,3,2,5,2,6,0,4,0,-2,-1,2,0,-1,-2,-4,-1)
Person2 <- c(-4,-3,4,-5,-1,-1,-2,2,1,0,3,2,3,-4,2,-1,2,-1,4,-2,6,-2,-1,-2,-1,-1,-3,5,2,-1,3,3,1,-3,1,3,-3,2,-2,4,-4,-6,-4,-7,0,-3,1,-2,0,2,-5,2,-2,-1,4,1,1,0,1,5,1,0,1,1,0,2,0,7,-2,3,-1,-2,-3,0,0,0,0)
df <- data.frame(cbind(Person1, Person2))
g <- ggplot(data = df, mapping = aes(x = Person1, y = Person2))
g <- g + geom_point(alpha = 1/3)  # alpha b/c of overplotting
g <- g + geom_smooth(method = "lm")  # just for comparison
g <- g + coord_fixed()  # otherwise, the angles of vectors are off
g

corrplot para mis datos

Observe que, por medición, estos datos:

  • ... tiene una media de cero,
  • ... es perfectamente simétrico,
  • ... y está igualmente escalado en ambas variables (no debería haber diferencia entre la correlación y la matriz de covarianza)

Ahora, quiero combinar las dos parcelas anteriores .

corre <- cor(x = df$Person1, y = df$Person2, method = "spearman")  # calculate correlation, must be spearman b/c of measurement
matrix <- matrix(c(1, corre, corre, 1), nrow = 2)  # make this into a matrix
eigen <- eigen(matrix)  # calculate eigenvectors and values
eigen

da

> $values
> [1] 1.6 0.4
>
> $vectors
>     [,1]  [,2]
> [1,] 0.71 -0.71
> [2,] 0.71  0.71
>
> $vectors.scaled
>     [,1]  [,2]
> [1,]  0.9 -0.45
> [2,]  0.9  0.45

y, siguiendo adelante

g <- g + stat_ellipse(type = "norm")
  # add ellipse, though I am not sure which is the adequate type
  # as per https://github.com/hadley/ggplot2/blob/master/R/stat-ellipse.R
eigen$slopes[1] <- eigen$vectors[1,1]/eigen$vectors[2,1]  # calc slopes as ratios
eigen$slopes[2] <- eigen$vectors[1,1]/eigen$vectors[1,2]  # calc slopes as ratios
g <- g + geom_abline(intercept = 0, slope = eigen$slopes[1], colour = "green")  # plot pc1
g <- g + geom_abline(intercept = 0, slope = eigen$slopes[2], colour = "red")  # plot pc2
g <- g + geom_segment(x = 0, y = 0, xend = eigen$values[1], yend = eigen$slopes[1] * eigen$values[1], colour = "green", arrow = arrow(length = unit(0.2, "cm")))  # add arrow for pc1
g <- g + geom_segment(x = 0, y = 0, xend = eigen$values[2], yend = eigen$slopes[2] * eigen$values[2], colour = "red", arrow = arrow(length = unit(0.2, "cm")))  # add arrow for pc2
# Here come the perpendiculars, from StackExchange answer /programming/30398908/how-to-drop-a-perpendicular-line-from-each-point-in-a-scatterplot-to-an-eigenv ===
perp.segment.coord <- function(x0, y0, a=0,b=1){
#finds endpoint for a perpendicular segment from the point (x0,y0) to the line
# defined by lm.mod as y=a+b*x
  x1 <- (x0+b*y0-a*b)/(1+b^2)
  y1 <- a + b*x1
  list(x0=x0, y0=y0, x1=x1, y1=y1)
}
ss <- perp.segment.coord(df$Person1, df$Person2, 0, eigen$slopes[1])
g <- g + geom_segment(data=as.data.frame(ss), aes(x = x0, y = y0, xend = x1, yend = y1), colour = "green", linetype = "dotted")
g

Trama final

¿Este gráfico ilustra adecuadamente la extracción de vector propio / valor propio en PCA?

  • No estoy seguro de cuáles serían las elipses adecuadas y / o la longitud de los vectores (¿o no importa?)
  • Supongo que los vectores tienen una pendiente de 1, -1se debe a mis datos (clasificación? Simetría?), Y diferirían para otros datos.

Ps .: esto se basa en el tutorial anterior y esta pregunta CrossValidated .

Pps .: los perpendiculares soltados en el vector son cortesía de esta respuesta de StackExchange

maxheld
fuente
3
No escale sus vectores propios; luego vuelve a dibujar la trama. Creo que entonces verás de inmediato dónde cometiste un error.
whuber
gracias @whuber, lo arregló. Necesitaba tomar la relación de los dos vectores propios. ¿Se ve mejor ahora? ¿Cualquier otra sugerencia? (Supongo que las pendientes son exactamente -1, 1 se debe a mis datos extraños).
maxheld
3
Cuando solo hay dos variables, los vectores propios estandarizados son siempre (1/ /2,±1/ /2), que, como dice la teoría, son ortogonales. Tu error es que las escalaste incorrectamente: deberías haber escalado las columnas en lugar de las filas.
whuber
@amoeba estuvo de acuerdo, tiene una respuesta del 95%. ¿Podría comentar sobre las dos últimas viñetas planteadas en la pregunta? 1) es el correcto y elipses 2) son 1, -1a esperarse pendientes?
maxheld

Respuestas:

2

No hay mucho que responder aquí. Parece que has tenido algunos problemas con tu script que ya están solucionados. Actualmente no hay nada malo con su visualización y, de hecho, me parece una ilustración muy agradable y adecuada.

Para responder sus preguntas restantes:

  1. Las pendientes de tus ejes principales siempre serán 1 y -1para un conjunto de datos bidimensional estandarizado (es decir, si está trabajando con una matriz de correlación), como dijo @whuber en los comentarios. Vea mi respuesta aquí: ¿una matriz de correlación de dos variables siempre tiene los mismos vectores propios?

  2. La elipse que trazaste (según mi entendimiento del código fuente de stat_ellipse()) es una elipse con una cobertura del 95%, suponiendo una distribución normal multivariada. Esta es una elección razonable. Tenga en cuenta que si desea una cobertura diferente, puede cambiarla a través del levelparámetro de entrada, pero el 95% es bastante estándar y está bien.

ameba
fuente