El PCA es una técnica estadística de la minería de datos que consiste en reducir la dimensión de un conjunto enorme de variables a un nuevo número menor llamadas componente principales o factores latentes, por medio de una búsqueda dentro de todas las dimensiones del dataset de aquellos componentes que sean los principales y definan la estructura básica, reemplazando así un número grande de variables que están correlacionadas entre sí con un número menor de variables que no tengan relación entre ellas, esto sin perder la mayor cantidad de información del modelo original.

#install.packages(“ade4”) #install.packages(“FactoMineR”) #install.packages(“factoextra”) #install.packages(“pander”) #install.packages(“wesanderson”)

Antes de implementar una minería de datos se debe realizar un análisis exploratorio de estos, ya que como el proceso busca principalmente reducir variables que puedan estar correlacionadas entre sí podemos verificar esto antes del PCA.

Primero obtenemos la información del set de datos USArrests del paquete básico de R.

data("USArrests")
head(USArrests)
##            Murder Assault UrbanPop Rape
## Alabama      13.2     236       58 21.2
## Alaska       10.0     263       48 44.5
## Arizona       8.1     294       80 31.0
## Arkansas      8.8     190       50 19.5
## California    9.0     276       91 40.6
## Colorado      7.9     204       78 38.7

Este conjunto de datos contiene el porcentaje de arrestos por cada 100,000 residentes por asalto, asesinato y violación en cada uno de los 50 estados de EE. UU. En 1973. También se da el porcentaje de la población que vive en áreas urbanas.

Vamos a ver si hay datos NA.

which(is.na(USArrests))
## integer(0)

Ahora observando la distribución de los datos solo asalto parece tener una asimetría positiva concentrando los datos un poco más en el lado inferior, es decir, una mayor dispersión. Respecto a los datos atípicos solo se es visible en rape.

library(wesanderson)
## Warning: package 'wesanderson' was built under R version 4.0.5
boxplot(USArrests, col = wes_palette(n=4, name="GrandBudapest2"),
        horizontal = FALSE,
        xlab = "Tipos de arrestos",  
        ylab = "Por cada 100.000 hab", 
        main = "Boxplot de los datos USArrests") 

Las estadísticas básicas nos muestran que en promedio hay tres veces más secuestros que asesinatos y ocho veces más asaltos que violaciones.

summary(USArrests)
##      Murder          Assault         UrbanPop          Rape      
##  Min.   : 0.800   Min.   : 45.0   Min.   :32.00   Min.   : 7.30  
##  1st Qu.: 4.075   1st Qu.:109.0   1st Qu.:54.50   1st Qu.:15.07  
##  Median : 7.250   Median :159.0   Median :66.00   Median :20.10  
##  Mean   : 7.788   Mean   :170.8   Mean   :65.54   Mean   :21.23  
##  3rd Qu.:11.250   3rd Qu.:249.0   3rd Qu.:77.75   3rd Qu.:26.18  
##  Max.   :17.400   Max.   :337.0   Max.   :91.00   Max.   :46.00

El análisis de correlación nos puede indicar un poco de correlación entre las variables indicando la posibilidad de eliminar alguna de las variables ya que esta información la suministra una de las existentes.

library(PerformanceAnalytics)
## Warning: package 'PerformanceAnalytics' was built under R version 4.0.5
## Loading required package: xts
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
## 
## Attaching package: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
## 
##     legend
chart.Correlation(USArrests,histogram = F ,pch = 19)

Al analizar la variabilidad de las columnas se destaca el gran tamaño de los asaltos, algo lógico por su gran magnitud y la ocurrencia ya que es el tipo de arresto más común.

apply(USArrests, 2, var)
##     Murder    Assault   UrbanPop       Rape 
##   18.97047 6945.16571  209.51878   87.72916

Pasa confirmar si se debe hacer un ACP se realiza una prueba formal, en este caso el test de correlación de Barlett, el cual se utiliza para probar si la hipótesis nula que afirma que las variables no están correlacionadas en la población es verdadera, es decir, comprueba si la matriz de correlaciones es una matriz de identidad.

H0: Las variables no están correlacionadas entre sí H1: Las variables están correlacionadas entre sí

library(psych)
## Warning: package 'psych' was built under R version 4.0.5
cortest.bartlett(USArrests, n = 50)
## R was not square, finding R from data
## $chisq
## [1] 88.28815
## 
## $p.value
## [1] 6.868423e-17
## 
## $df
## [1] 6

Al obtener un p-value menor a 0.05 no existe suficiente información para aceptar la hipótesis nula, por lo tanto la matriz de datos es válida para continuar con el proceso de análisis.

El test KMO relaciona los coeficientes de correlación observados entre las variables. Cuanto más cercano de 1 sea el valor KMO general e individual, mayor será la relación entre las variables.

KMO(USArrests)
## Kaiser-Meyer-Olkin factor adequacy
## Call: KMO(r = USArrests)
## Overall MSA =  0.65
## MSA for each item = 
##   Murder  Assault UrbanPop     Rape 
##     0.62     0.64     0.50     0.78

Obteniendo valores en su mayoría a 0.5, podemos afirmar que este conjunto es apto para la realización del análisis de componentes principales.

Al demostrar las diferencias entre varianzas lo mejor es realizar una estandarización de los datos para que todos estén en la misma magnitud, así que si existe una variable con varianza mayor al resto, entonces esta no influirá más que las otras en el análisis de los datos.

-> Estandarización = Se le resta a cada columna su media y se divide en su desviación estandar

Para realizar el ACP se tienen dos funciones para hacer esto: prcomp() y princomp, pero lo ideal es usar la primera porque es la que arroja resultados más precisos.

acp<-prcomp(USArrests,
             scale = TRUE)
print(acp)
## Standard deviations (1, .., p=4):
## [1] 1.5748783 0.9948694 0.5971291 0.4164494
## 
## Rotation (n x k) = (4 x 4):
##                 PC1        PC2        PC3         PC4
## Murder   -0.5358995  0.4181809 -0.3412327  0.64922780
## Assault  -0.5831836  0.1879856 -0.2681484 -0.74340748
## UrbanPop -0.2781909 -0.8728062 -0.3780158  0.13387773
## Rape     -0.5434321 -0.1673186  0.8177779  0.08902432
summary(acp)
## Importance of components:
##                           PC1    PC2     PC3     PC4
## Standard deviation     1.5749 0.9949 0.59713 0.41645
## Proportion of Variance 0.6201 0.2474 0.08914 0.04336
## Cumulative Proportion  0.6201 0.8675 0.95664 1.00000
names(acp)
## [1] "sdev"     "rotation" "center"   "scale"    "x"
head(acp$rotation)[, 1:4] #Las coordenadas de los datos en el nuevo sistema rotado de coordenadas. 
##                 PC1        PC2        PC3         PC4
## Murder   -0.5358995  0.4181809 -0.3412327  0.64922780
## Assault  -0.5831836  0.1879856 -0.2681484 -0.74340748
## UrbanPop -0.2781909 -0.8728062 -0.3780158  0.13387773
## Rape     -0.5434321 -0.1673186  0.8177779  0.08902432
#Estas coordenadas se corresponden con los scores de los componentes principales.
dim(acp$rotation) #Número de distintos componentes
## [1] 4 4
head(acp$x)[,1:4] #Los vectores de los scores
##                   PC1        PC2         PC3          PC4
## Alabama    -0.9756604  1.1220012 -0.43980366  0.154696581
## Alaska     -1.9305379  1.0624269  2.01950027 -0.434175454
## Arizona    -1.7454429 -0.7384595  0.05423025 -0.826264240
## Arkansas    0.1399989  1.1085423  0.11342217 -0.180973554
## California -2.4986128 -1.5274267  0.59254100 -0.338559240
## Colorado   -1.4993407 -0.9776297  1.08400162  0.001450164
acp$sdev^2
## [1] 2.4802416 0.9897652 0.3565632 0.1734301

Cada vez disminuye la proporción de varianza siendo los dos primeros quienes más acumulan. El criterio de Kelser indica que sabiendo que la transformación ortogonal se ha realizado a la matriz de correlación, la varianza de cada uno de los componentes principales debe ser 1 ya que si es menor esta no explicaría la suficiente variabilidad original.

scree(USArrests,main ="Grafico de Sedimentacion")

Con la información recolectada se puede concluir que lo mejor es seleccionar los dos primeros componentes como reemplazo de las 4 variables originales, con una explicación de la variabilidad original del 86%.

library(factoextra)
## Warning: package 'factoextra' was built under R version 4.0.5
## Loading required package: ggplot2
## Warning: package 'ggplot2' was built under R version 4.0.5
## 
## Attaching package: 'ggplot2'
## The following objects are masked from 'package:psych':
## 
##     %+%, alpha
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
var <- get_pca_var(acp)
var
## Principal Component Analysis Results for variables
##  ===================================================
##   Name       Description                                    
## 1 "$coord"   "Coordinates for the variables"                
## 2 "$cor"     "Correlations between variables and dimensions"
## 3 "$cos2"    "Cos2 for the variables"                       
## 4 "$contrib" "contributions of the variables"
var$contrib
##              Dim.1     Dim.2     Dim.3     Dim.4
## Murder   28.718825 17.487524 11.643977 42.149674
## Assault  34.010315  3.533859  7.190358 55.265468
## UrbanPop  7.739016 76.179065 14.289594  1.792325
## Rape     29.531844  2.799553 66.876071  0.792533

Para el análisis gráfico tenemos una variedad de representaciones que permiten observar la ubicación y proporción explicativa de los componentes.

Iniciamos por el más simple, esta es una representación bidimensional de los dos componentes.

biplot(x = acp, scale = 0, cex = 0.6, col = c("dodgerblue3", "deeppink3"))

El PC1 explica mejor los 3 motivos de arresto y PC2 la población urbana.

fviz_pca_ind(acp, geom.ind = "point", 
             col.ind = "#FC4E07", 
             axes = c(1, 2), 
             pointsize = 1.5) 

fviz_pca_var(acp, col.var = "cos2", 
             geom.var = "arrow", 
             labelsize = 2, 
             repel = FALSE)

Porcentaje de explicación de los eigenvalues ordenados de mayor a menor.

fviz_screeplot(acp, addlabels = TRUE, ylim = c(0, 100))

Este nos marca el valor medio de la contribución de la variable a el componente, las variables mayores al límite pueden considerarse importantes al momento de contribuir.

fviz_contrib(acp, choice = "var", axes = 1, top = 4)

fviz_contrib(acp, choice = "var", axes = 2, top = 4)

Ahora guardamos en un vector los componentes.

PC1<-acp[[2]][,1]
PC2<- acp[[2]][,2]
Individuos<-acp$x[,1:2]
head(Individuos)
##                   PC1        PC2
## Alabama    -0.9756604  1.1220012
## Alaska     -1.9305379  1.0624269
## Arizona    -1.7454429 -0.7384595
## Arkansas    0.1399989  1.1085423
## California -2.4986128 -1.5274267
## Colorado   -1.4993407 -0.9776297
Componentes<-cbind(PC1,PC2)
head(Componentes)
##                 PC1        PC2
## Murder   -0.5358995  0.4181809
## Assault  -0.5831836  0.1879856
## UrbanPop -0.2781909 -0.8728062
## Rape     -0.5434321 -0.1673186

Esta es una forma de graficar en el círculo de correlación cuando tenemos 3 componentes.

library(ade4)
## Warning: package 'ade4' was built under R version 4.0.5
s.corcircle(Componentes[,-3], sub = "PC1 y PC2", possub = "topright")

s.label(Individuos[,-3], label = row.names(USArrests), sub = "Coordenadas de los individuos")

Si se quiere graficar solo 2 componentes entre una cantidad muy grande, lo ideal sería: s.corcicle(Componentes[, c(-1, -4, -5, -6, -7, -8, -9)]

Para finalizar, se modifica la base de datos inicial con los componentes seleccionados concluyendo la reducción de la dimensionalidad inicial.

pc1<- apply(acp$rotation[,1]*USArrests, 1, sum)
pc2<- apply(acp$rotation[,2]*USArrests, 1, sum)
USArrests$PC1 <- pc1
USArrests$PC2 <- pc2
USArrests[,1:4] <-  NULL
head(USArrests)
##                  PC1        PC2
## Alabama    -109.7067 -194.71128
## Alaska     -200.9300  -40.54732
## Arizona    -198.6759   59.01456
## Arkansas   -154.1308   29.54465
## California -141.6652 -234.51235
## Colorado   -181.9864  -24.46027