Para comenzar este análisis de datos, importamos la librería ggplot; esto es para poder visualizar de mejor manera los gráficos.

Los datos son sobre los arrestos por 100,000 ciudadanos en Estados Unidos por asalto, homicidios y secuestros en 50 estados en 1973. Este dato corresponde al porcentaje de la población que vive en zonas urbanas.

Se implementa la función scale, una herramienta diseñada para centrar y escalar las columnas de un dataframe numérico. Este funciona con la siguiente fórmula.

\[ z = \frac{x - \bar{x}}{s} \]

Donde:

Es decir, los datos están “centrados” en el origen.

Ya que están centrados, calcula la desviación estándar de los datos. Divide cada número entre la desviación y haz la dispersión de los datos uniformemente (unidad de medida igual a 1).

También la función devuelve lo siguiente:

scaled:center: El valor que se usó para restar (la media).

scaled:scale: El valor que se usó para dividir (la desviación estándar).

library(ggplot2)
data("USArrests")

# It is recommended to scale the data
usarrests_scaled <- scale(USArrests)
print(usarrests_scaled)
##                     Murder     Assault    UrbanPop         Rape
## Alabama         1.24256408  0.78283935 -0.52090661 -0.003416473
## Alaska          0.50786248  1.10682252 -1.21176419  2.484202941
## Arizona         0.07163341  1.47880321  0.99898006  1.042878388
## Arkansas        0.23234938  0.23086801 -1.07359268 -0.184916602
## California      0.27826823  1.26281442  1.75892340  2.067820292
## Colorado        0.02571456  0.39885929  0.86080854  1.864967207
## Connecticut    -1.03041900 -0.72908214  0.79172279 -1.081740768
## Delaware       -0.43347395  0.80683810  0.44629400 -0.579946294
## Florida         1.74767144  1.97077766  0.99898006  1.138966691
## Georgia         2.20685994  0.48285493 -0.38273510  0.487701523
## Hawaii         -0.57123050 -1.49704226  1.20623733 -0.110181255
## Idaho          -1.19113497 -0.60908837 -0.79724965 -0.750769945
## Illinois        0.59970018  0.93883125  1.20623733  0.295524916
## Indiana        -0.13500142 -0.69308401 -0.03730631 -0.024769429
## Iowa           -1.28297267 -1.37704849 -0.58999237 -1.060387812
## Kansas         -0.41051452 -0.66908525  0.03177945 -0.345063775
## Kentucky        0.43898421 -0.74108152 -0.93542116 -0.526563903
## Louisiana       1.74767144  0.93883125  0.03177945  0.103348309
## Maine          -1.30593210 -1.05306531 -1.00450692 -1.434064548
## Maryland        0.80633501  1.55079947  0.10086521  0.701231086
## Massachusetts  -0.77786532 -0.26110644  1.34440885 -0.526563903
## Michigan        0.99001041  1.01082751  0.58446551  1.480613993
## Minnesota      -1.16817555 -1.18505846  0.03177945 -0.676034598
## Mississippi     1.90838741  1.05882502 -1.48810723 -0.441152078
## Missouri        0.27826823  0.08687549  0.30812248  0.743936999
## Montana        -0.41051452 -0.74108152 -0.86633540 -0.515887425
## Nebraska       -0.80082475 -0.82507715 -0.24456358 -0.505210947
## Nevada          1.01296983  0.97482938  1.06806582  2.644350114
## New Hampshire  -1.30593210 -1.36504911 -0.65907813 -1.252564419
## New Jersey     -0.08908257 -0.14111267  1.62075188 -0.259651949
## New Mexico      0.82929443  1.37080881  0.30812248  1.160319648
## New York        0.76041616  0.99882813  1.41349461  0.519730957
## North Carolina  1.19664523  1.99477641 -1.41902147 -0.547916860
## North Dakota   -1.60440462 -1.50904164 -1.48810723 -1.487446939
## Ohio           -0.11204199 -0.60908837  0.65355127  0.017936483
## Oklahoma       -0.27275797 -0.23710769  0.16995096 -0.131534211
## Oregon         -0.66306820 -0.14111267  0.10086521  0.861378259
## Pennsylvania   -0.34163624 -0.77707965  0.44629400 -0.676034598
## Rhode Island   -1.00745957  0.03887798  1.48258036 -1.380682157
## South Carolina  1.51807718  1.29881255 -1.21176419  0.135377743
## South Dakota   -0.91562187 -1.01706718 -1.41902147 -0.900240639
## Tennessee       1.24256408  0.20686926 -0.45182086  0.605142783
## Texas           1.12776696  0.36286116  0.99898006  0.455672088
## Utah           -1.05337842 -0.60908837  0.99898006  0.178083656
## Vermont        -1.28297267 -1.47304350 -2.31713632 -1.071064290
## Virginia        0.16347111 -0.17711080 -0.17547783 -0.056798864
## Washington     -0.86970302 -0.30910395  0.51537975  0.530407436
## West Virginia  -0.47939280 -1.07706407 -1.83353601 -1.273917376
## Wisconsin      -1.19113497 -1.41304662  0.03177945 -1.113770203
## Wyoming        -0.22683912 -0.11711392 -0.38273510 -0.601299251
## attr(,"scaled:center")
##   Murder  Assault UrbanPop     Rape 
##    7.788  170.760   65.540   21.232 
## attr(,"scaled:scale")
##    Murder   Assault  UrbanPop      Rape 
##  4.355510 83.337661 14.474763  9.366385
Significa:

Cada valor es diferente y no importa si es positivo o negativo, ya que por cada estado hay una diferente densidad poblacional; es decir, toma una media en general y puede haber menos asesinatos en un estado que en otro, como por ejemplo

max(usarrests_scaled)
## [1] 2.64435

Nevada, que tiene 2.64435, a New Hampshire, que tiene -1.252564419. Estos tienen bastante diferencia debido a que New Hampshire está por debajo de la media.

Ya que se comprendieron estos datos, podemos hacer K-means, método que divide las observaciones en k grupos de tal manera que las observaciones dentro de un mismo grupo sean lo más similares posible, y las de grupos diferentes sean lo más distintas posible.

En este caso hacemos k-means escalado debido a que es un algoritmo basado puramente en geometría y distancias. K-means usa la distancia euclidiana:

\[ d(p, q) = \sqrt{\sum_{i=1}^{n} (p_i - q_i)^2} \]

Esto es que, si una variable tiene un rango de 0 a 1,000,000 y otra de 0 a 10, como por ejemplo de 0 a 1,000,000 (asesinatos en un estado) y otra de 0 a 10 (secuestros), la variable de asesinatos dominará completamente el cálculo.

La diferencia de unos pocos miles de asesinados pesará más que toda la escala de educación, haciendo que el algoritmo ignore por completo la segunda variable.

COMPARACIÓN:

SCALED

# Now, let´s run the K-means
set.seed(123)
km_sc <- kmeans(usarrests_scaled, centers = 3, nstart = 25)

km_sc$cluster
##        Alabama         Alaska        Arizona       Arkansas     California 
##              1              1              1              3              1 
##       Colorado    Connecticut       Delaware        Florida        Georgia 
##              1              3              3              1              1 
##         Hawaii          Idaho       Illinois        Indiana           Iowa 
##              3              2              1              3              2 
##         Kansas       Kentucky      Louisiana          Maine       Maryland 
##              3              2              1              2              1 
##  Massachusetts       Michigan      Minnesota    Mississippi       Missouri 
##              3              1              2              1              1 
##        Montana       Nebraska         Nevada  New Hampshire     New Jersey 
##              2              2              1              2              3 
##     New Mexico       New York North Carolina   North Dakota           Ohio 
##              1              1              1              2              3 
##       Oklahoma         Oregon   Pennsylvania   Rhode Island South Carolina 
##              3              3              3              3              1 
##   South Dakota      Tennessee          Texas           Utah        Vermont 
##              2              1              1              3              2 
##       Virginia     Washington  West Virginia      Wisconsin        Wyoming 
##              3              3              2              2              3

NOT SCALED

library(ggplot2)
data("USArrests")

set.seed(123)
km_sc2 <- kmeans(USArrests, centers = 3, nstart = 25)

km_sc2$cluster
##        Alabama         Alaska        Arizona       Arkansas     California 
##              1              1              1              3              1 
##       Colorado    Connecticut       Delaware        Florida        Georgia 
##              3              2              1              1              3 
##         Hawaii          Idaho       Illinois        Indiana           Iowa 
##              2              2              1              2              2 
##         Kansas       Kentucky      Louisiana          Maine       Maryland 
##              2              2              1              2              1 
##  Massachusetts       Michigan      Minnesota    Mississippi       Missouri 
##              3              1              2              1              3 
##        Montana       Nebraska         Nevada  New Hampshire     New Jersey 
##              2              2              1              2              3 
##     New Mexico       New York North Carolina   North Dakota           Ohio 
##              1              1              1              2              2 
##       Oklahoma         Oregon   Pennsylvania   Rhode Island South Carolina 
##              3              3              2              3              1 
##   South Dakota      Tennessee          Texas           Utah        Vermont 
##              2              3              3              2              2 
##       Virginia     Washington  West Virginia      Wisconsin        Wyoming 
##              3              3              2              2              3
Habiendo elegido tres centros para agrupar los estados en relación a los arrestos, la diferencia principal entre los datos escalados y no escalados se basa en el conjunto donde fueron agrupados.
Por ejemplo:

Mientras que los estados escalados de KANSAS, CONNECTICUT, DELAWERE, PENNSYLVANIA, etc., fueron designados al clúster #tres (3), los datos no escalados agruparon a KANSAS, CONNECTICUT, PENNSYLVANIA en el grupo dos (2), y a DELAWERE en el grupo uno (1).

km_sc$centers #SCALED
##       Murder    Assault   UrbanPop       Rape
## 1  1.0049340  1.0138274  0.1975853  0.8469650
## 2 -0.9615407 -1.1066010 -0.9301069 -0.9667633
## 3 -0.4469795 -0.3465138  0.4788049 -0.2571398
km_sc2$centers #NOT SCALED
##      Murder  Assault UrbanPop     Rape
## 1 11.812500 272.5625 68.31250 28.37500
## 2  4.270000  87.5500 59.75000 14.39000
## 3  8.214286 173.2857 70.64286 22.84286
Las tablas acceden a los clústeres y a la distancia a sus centros. Aquellos datos escalados tienen distancias más cortas y parecidas entre ellas. Mientras que los datos no escalados se dispersan en valores muy altos y diferentes, es por esta razón que el algoritmo categorizó de distintas formas los estados a los clusters.

¿Cómo hace esto?

El algoritmo selecciona una k, inicializa los k por centroides y asigna cada observación al centroide más cercano y así va recalculando, repitiéndolo hasta que no cambie mucho la distancia. En este caso, el grupo 3 fue el que más estuvo uniforme dentro de los 4 delitos; estados como Arkansas, Oregón o Pensilvania son los que tienen estos 4 delitos de manera recurrente.

Ya que hicimos el k-means para agrupar los datos en 3 categorías, hacemos el Within-Cluster Sum of Squares o, por sus siglas, WCSS; este nos puede ayudar a contestar la pregunta acerca de ¿en cuántos grupos debo dividir mis datos? Siendo así una medida de cohesión. Nos dice qué tan “apretaditos” o compactos están los puntos dentro de cada clúster.

\[ WCSS = \sum_{i=1}^{k} \sum_{x \in C_i} \|x - \mu_i\|^2 \]

Ya con esto graficamos por medio de la gráfica de tipo Elbow Method; esta gráfica es una técnica visual que usamos para encontrar el equilibrio perfecto entre tener un WCSS bajo y no tener demasiados clústeres.

SCALED

wss_sc = numeric(10)
for (k in 1:10) {
  set.seed(123)
  wss_sc[k] <- kmeans(usarrests_scaled, centers = k, nstart = 25)$tot.withinss
}

plot(1:10, wss_sc, type = "b", pch = 19,
     xlab = "Number of clusters (k) ",
     ylab = "Total within-cluster sum of squares",
     main = "Elbow Method for K-means - SCALED")

NOT SCALED

wss_sc = numeric(10)
for (k in 1:10) {
  set.seed(123)
  wss_sc[k] <- kmeans(USArrests, centers = k, nstart = 25)$tot.withinss
}

plot(1:10, wss_sc, type = "b", pch = 19,
     xlab = "Number of clusters (k)",
     ylab = "Total within-cluster sum of squares ",
     main = "Elbow Method for K-means  -NON SCALED")

Notamos que la gráfica cae y tiene un punto de inflexión haciendo la forma de un codo. Esto se puede interpretar como que antes del codo añade un clúster que reduce significativamente el error. Después del codo, si añadimos más clústeres, solo reduce el error de forma significativa (esto es sobreajustar).

El WCSS es la métrica de calidad, y la gráfica nos sirve para tomar una decisión para elegir el valor óptimo de 𝑘.

Encontramos que, entre las gráficas de codo, los datos no escalados contienen un WSS con valores muy grandes que nos indican una gran varianza o distancia entre los puntos y el centroide.

Los datos escalados se ven mejor distribuidos en la gráfica, con un codo menos pronunciado y valores WSS menores.

A pesar de esto, ambas gráficas nos sugieren que los valores adecuados para K están entre 2 y 4. La escala es más fácil de leer para encontrar EL valor K.

PCA

Ahora pasaremos a analizar estos datos con PCA:

Los principales componentes de análisis son una técnica de reducción de dimensiones que identifica direcciones, o los denominados componentes principales, que son combinaciones lineales de las variables originales.

Matemáticamente, lo que hace es lo siguiente: I. El primer componente principal es la dirección en el espacio a lo largo de la cual las proyecciones presentan la mayor varianza. II. El segundo componente principal es la dirección que maximiza la varianza entre todas las direcciones ortogonales a la primera. III. El k-ésimo componente es la dirección que maximiza la varianza y es ortogonal a los k − 1 componentes anteriores.

Básicamente, es una técnica para simplificar datos complejos sin perder la información más importante.

SCALED

# ------------------------------------------
# Now let´s work the PCA on this dataset
# ------------------------------------------
# Note that we use scale = TRUE because variables are on different scales
pca <- prcomp(USArrests, scale. = TRUE)

# Summary
summary(pca)
## 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

NOT SCALED

# ------------------------------------------
# Now let´s work the PCA on this dataset
# ------------------------------------------

pca2 <- prcomp(USArrests)

# Summary
summary(pca2)
## Importance of components:
##                            PC1      PC2    PC3     PC4
## Standard deviation     83.7324 14.21240 6.4894 2.48279
## Proportion of Variance  0.9655  0.02782 0.0058 0.00085
## Cumulative Proportion   0.9655  0.99335 0.9991 1.00000

Scree plot

El scree plot compara las PCAs de los datos y nos muestra cómo se proyecta la proporción de varianzas para cuatro variables.

Podemos observar que las primeras dos son aquellas con los valores más altos, mientras que las otras quedan casi al ras del eje Y. Esto nos indica que en nuestro modelo, las variables 1 y 2 son… explican más sobre nuestros datos y tienen más información que ruido.

Se puede complementar con la tabla de importancia de los componentes vistos previamente, que nos indica cómo la variable PCE1 explica el 62% de los arrestos en Estados Unidos y el PCO2 un 24% de los arrestos (en conjunto, 88%). Los otros valores porcentuales parecen ser bastante insignificantes. En otras palabras, nos indica que la naturaleza de los datos cambia en su mayoría en dirección a estas variables.

SCALED

# Scree plot
plot(pca, type = "l", main = "Scree Plot SCALED")

# Variance explained
var_explained <- pca$sdev^2 / sum(pca$sdev^2)

# PCA Variance plotted
plot(var_explained, type = "b", pch = 19,
     xlab = "Principal Component",
     ylab = "Proportion of Variance Explained",
     main = "Variance Explained by Principal Components SCALED")

## NOT SCALED

# Scree plot
plot(pca2, type = "l", main = "Scree Plot- not SCALED")

# Variance explained
var_explained <- pca2$sdev^2 / sum(pca2$sdev^2)

# PCA Variance plotted
plot(var_explained, type = "b", pch = 19,
     xlab = "Principal Component",
     ylab = "Proportion of Variance Explained",
     main = "Variance Explained by Principal Components -not SCALED")

Recordemos que:
  • PC1 de 0.6201 significa que el primer componente por sí solo eclipsa el 62.01% de toda la información del dataset original.

La proporción acumulativa de 0.8675 dice que si usamos PC1 y PC2 juntos, se mantiene el 86.75% de la información original.

Comparando con los datos no escalados:

Se observa que se disparan los valores en el eje Y de 0 a 7000. Esto reafirma que nuestros datos originales tienen mucha diferencia de varianza entre ellos.

También ejemplifica que los datos se encuentran en su mayoría en la primera variable con una proporción de varianza del 96% (Tabla de Importancia de los componentes).
Tomar estos datos como buenos resultaría en excluir la nfluencia de la influenza de las variables con otro tipo de crimen y atribuirlo completamente a uno solo.

En general, el codo en el scree plot parece estar en el componente 2, y nos da un buen acercamiento visual para rectificar que, a partir del componente 3, la ganancia de información es muy pequeña.

Gráficas de proporción

Las gráficas de proporción son muy similares al scree plot; solo cambia el uso de eigenvalores.

Para aquellos datos escalados en el eje Y, tenemos la varianza en relación a 1, mostrándose la dominancia del PC1 con un valor de 2.5 y con la posibilidad de aún usar PC2.

Para los datos no escalados, la varianza de PC1 en relación a los valores de PC2 se lanza hasta 7000.

SCALED

# PCA scores plot
plot(pca$x[,1], pca$x[,2],
     pch = 19,
     xlab = "PC1",
     ylab = "PC2",
     main = "PCA of USArrests")
text(pca$x[,1], pca$x[,2], labels = rownames(USArrests), pos = 3, cex = 0.7)

# ------------------------------------------
# Cool approach: K-means clusters on PCA space
# ------------------------------------------
plot(pca$x[,1], pca$x[,2],
     col = km_sc$cluster,
     pch = 19,
     xlab = "PC1",
     ylab = "PC2",
     main = "K-means Clusters Visualized on PCA Space")
text(pca$x[,1], pca$x[,2], labels = rownames(USArrests), pos = 3, cex = 0.7)

Como ya lo observamos en la gráfica de proporción, la gráfica de tipo mapa de posicionamiento nos arroja que los estados en el espacio de componentes principales nos dan una estructura clara.

El PC1 actúa como un indicador de crímenes, separando a los estados de alta incidencia (izquierda) de los de baja incidencia (derecha).
Igualmente, el PC2 refleja cuántos habitantes hay en el estado.

Gracias a esto podemos ver los grupos geográficos y cómo la alta tasa de arrestos se diferencia por estado.

NON SCALED

# PCA scores plot
plot(pca2$x[,1], pca2$x[,2],
     pch = 19,
     xlab = "PC1",
     ylab = "PC2",
     main = "PCA of USArrests")
text(pca2$x[,1], pca2$x[,2], labels = rownames(USArrests), pos = 3, cex = 0.7)

# ------------------------------------------
# Cool approach: K-means clusters on PCA space
# ------------------------------------------
plot(pca2$x[,1], pca2$x[,2],
     col = km_sc2$cluster,
     pch = 19,
     xlab = "PC1",
     ylab = "PC2",
     main = "K-means Clusters Visualized on PCA Space")
text(pca2$x[,1], pca2$x[,2], labels = rownames(USArrests), pos = 3, cex = 0.7)

En esta gráfica, los componentes principales (PC1 en el eje x y PC2 en el eje y) presentan intervalos más amplios.

Esto ocurre porque toma los valores de las variables como el número de crímenes cometidos en vez de evaluarlos en relación a su promedio por estado.

Como consecuencia, las variables con mayor escala tienen un peso excesivo en la proyección y algunos estados son categorizados incorrectamente.

Observamos esto al comparar las gráficas obtenidas con datos escalados vs. aquellos sin escalar.

SCALED

library(ggplot2)

pca_df <- data.frame(
  PC1 = pca$x[,1],
  PC2 = pca$x[,2],
  Cluster = factor(km_sc$cluster),
  State = rownames(USArrests)
)

ggplot(pca_df, aes(x = PC1, y = PC2, color = Cluster, label = State)) +
  geom_point(size = 3) +
  geom_text(vjust = -0.5, size = 3) +
  labs(
    title = "K-means Clusters in PCA Space",
    x = "Principal Component 1",
    y = "Principal Component 2"
  ) +
  theme_minimal(base_size = 14)

NOT SCALED

library(ggplot2)

pca_df <- data.frame(
  PC1 = pca2$x[,1],
  PC2 = pca2$x[,2],
  Cluster = factor(km_sc2$cluster),
  State = rownames(USArrests)
)

ggplot(pca_df, aes(x = PC1, y = PC2, color = Cluster, label = State)) +
  geom_point(size = 3) +
  geom_text(vjust = -0.5, size = 3) +
  labs(
    title = "K-means Clusters in PCA Space",
    x = "Principal Component 1",
    y = "Principal Component 2"
  ) +
  theme_minimal(base_size = 14)

Para concluir, la gráfica de tipo mapa de posicionamiento y la librería ggplot nos permiten una mejor visualización del gráfico. El Cluster 1 agrupa estados críticos con muchos delitos, el Cluster 2 identifica los estados con mayor seguridad y el Cluster 3 representa un punto medio.