Cluster. K-mean

Análisis de cluster. Códigos

K-means

En este ejemplo trabajaremos con el conjunto de datos “USArrest” que está precargado en R.

# Cargar la base de datos USArrests
data(USArrests)

Inspecciono el conjunto de datos

# Mostrar las primeras filas de la base de datos

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

También inspecciono el contenido completo

glimpse(USArrests)
## Rows: 50
## Columns: 4
## $ Murder   <dbl> 13.2, 10.0, 8.1, 8.8, 9.0, 7.9, 3.3, 5.9, 15.4, 17.4, 5.3, 2.~
## $ Assault  <int> 236, 263, 294, 190, 276, 204, 110, 238, 335, 211, 46, 120, 24~
## $ UrbanPop <int> 58, 48, 80, 50, 91, 78, 77, 72, 80, 60, 83, 54, 83, 65, 57, 6~
## $ Rape     <dbl> 21.2, 44.5, 31.0, 19.5, 40.6, 38.7, 11.1, 15.8, 31.9, 25.8, 2~

Puede observarse que la magnitud en que están expresadas las variables no es homogénea. En ese caso es necesario aplicar cualquiera de los métodos conocidos para estandarizar las variables. Voy a emplear puntuaciones z. En R existe una función que ayuda con este procedimiento:

# Escalar los datos es crucial para que todas las variables tengan la misma importancia
# Esto evita que variables con rangos más grandes dominen el cálculo de distancias

# guardo el resultado en un objeto que llamare "df"
df <- scale(USArrests)

Inspecciono nuevamente

glimpse(df)
##  num [1:50, 1:4] 1.2426 0.5079 0.0716 0.2323 0.2783 ...
##  - attr(*, "dimnames")=List of 2
##   ..$ : chr [1:50] "Alabama" "Alaska" "Arizona" "Arkansas" ...
##   ..$ : chr [1:4] "Murder" "Assault" "UrbanPop" "Rape"
##  - attr(*, "scaled:center")= Named num [1:4] 7.79 170.76 65.54 21.23
##   ..- attr(*, "names")= chr [1:4] "Murder" "Assault" "UrbanPop" "Rape"
##  - attr(*, "scaled:scale")= Named num [1:4] 4.36 83.34 14.47 9.37
##   ..- attr(*, "names")= chr [1:4] "Murder" "Assault" "UrbanPop" "Rape"

El siguiente paso consiste en determinar el número óptimo de conglomerados (K). Para ello emplearé el “Método del codo (Elbow method)” para encontrar el K óptimo. Se calcula la suma total de cuadrados dentro de los conglomerados (tot.withinss) para diferentes valores de K.

set.seed(123) # Para reproducibilidad de los resultados aleatorios
wss <- (nrow(df)-1)*sum(apply(df,2,var))
for (i in 2:15) {
  wss[i] <- sum(kmeans(df, centers=i, nstart=25)$withinss)
}

Grafico el método del codo:

plot(1:15, wss, type="b", xlab="Número de Clusters (K)",
     ylab="Suma de Cuadrados Intra-Cluster",
     main="Método del Codo para K-means en USArrests")

En este gráfico, se busca un “codo” donde la disminución de la suma de cuadrados intra-cluster se ralentiza significativamente. Esto sugiere un K apropiado. Para USArrests, K=4 es un punto de inflexión común.

Asumiendo K=4 por el método del codo, nstart=25 significa que el algoritmo se ejecutará 25 veces con diferentes centroides iniciales y se elegirá la mejor solución (la que tenga la menor suma de cuadrados intra-cluster total), lo que ayuda a evitar óptimos locales.

km.res <- kmeans(df, centers = 4, nstart = 25)

El siguiente paso consiste en interpretar los resultados

km.res
## K-means clustering with 4 clusters of sizes 13, 13, 8, 16
## 
## Cluster means:
##       Murder    Assault   UrbanPop        Rape
## 1 -0.9615407 -1.1066010 -0.9301069 -0.96676331
## 2  0.6950701  1.0394414  0.7226370  1.27693964
## 3  1.4118898  0.8743346 -0.8145211  0.01927104
## 4 -0.4894375 -0.3826001  0.5758298 -0.26165379
## 
## Clustering vector:
##        Alabama         Alaska        Arizona       Arkansas     California 
##              3              2              2              3              2 
##       Colorado    Connecticut       Delaware        Florida        Georgia 
##              2              4              4              2              3 
##         Hawaii          Idaho       Illinois        Indiana           Iowa 
##              4              1              2              4              1 
##         Kansas       Kentucky      Louisiana          Maine       Maryland 
##              4              1              3              1              2 
##  Massachusetts       Michigan      Minnesota    Mississippi       Missouri 
##              4              2              1              3              2 
##        Montana       Nebraska         Nevada  New Hampshire     New Jersey 
##              1              1              2              1              4 
##     New Mexico       New York North Carolina   North Dakota           Ohio 
##              2              2              3              1              4 
##       Oklahoma         Oregon   Pennsylvania   Rhode Island South Carolina 
##              4              4              4              4              3 
##   South Dakota      Tennessee          Texas           Utah        Vermont 
##              1              3              2              4              1 
##       Virginia     Washington  West Virginia      Wisconsin        Wyoming 
##              4              4              1              1              4 
## 
## Within cluster sum of squares by cluster:
## [1] 11.952463 19.922437  8.316061 16.212213
##  (between_SS / total_SS =  71.2 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"

Para evitar tener de un “solo golpe” todo el resultado se puede proceder de la siguiente manera:

#centroides
km.res$centers
##       Murder    Assault   UrbanPop        Rape
## 1 -0.9615407 -1.1066010 -0.9301069 -0.96676331
## 2  0.6950701  1.0394414  0.7226370  1.27693964
## 3  1.4118898  0.8743346 -0.8145211  0.01927104
## 4 -0.4894375 -0.3826001  0.5758298 -0.26165379

los centroides de los clusters (medias para cada variable en cada cluster) representan las características promedio de cada conglomerado.

Veamos ahora el tamaño de cada cluster:

km.res$size
## [1] 13 13  8 16

El tamaño de cada cluster es el número de individuos, en esta caso de estados, en cada conglomerado

Ahora, observamos a qué cluster pertenece cada estado:

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

Lo ideal es ver esos clusters en el conjunto de datos inicial. Para ello procedo de la siguiente forma:

# Añadir la asignación de cluster al data frame original para un análisis más fácil
USArrests_clustered <- cbind(USArrests, cluster = km.res$cluster)

Inspecciono:

glimpse(USArrests_clustered)
## Rows: 50
## Columns: 5
## $ Murder   <dbl> 13.2, 10.0, 8.1, 8.8, 9.0, 7.9, 3.3, 5.9, 15.4, 17.4, 5.3, 2.~
## $ Assault  <int> 236, 263, 294, 190, 276, 204, 110, 238, 335, 211, 46, 120, 24~
## $ UrbanPop <int> 58, 48, 80, 50, 91, 78, 77, 72, 80, 60, 83, 54, 83, 65, 57, 6~
## $ Rape     <dbl> 21.2, 44.5, 31.0, 19.5, 40.6, 38.7, 11.1, 15.8, 31.9, 25.8, 2~
## $ cluster  <int> 3, 2, 2, 3, 2, 2, 4, 4, 2, 3, 4, 1, 2, 4, 1, 4, 1, 3, 1, 2, 4~

Ahora lo importante es visualizar este resultado:

# Se utiliza el paquete 'factoextra' para una visualización más rica. Si no está instalada, descomentar la siguiente línea:
# install.packages("factoextra")
library(factoextra)
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
fviz_cluster(km.res, data = df,
             palette = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"), # Colores para los clusters
             ellipse.type = "euclid", # Dibuja elipses alrededor de los clusters basadas en la distancia euclidiana
             star.plot = TRUE, # Dibuja líneas desde cada punto a su centroide
             repel = TRUE, # Evita la superposición de etiquetas de texto
             ggtheme = theme_minimal(), # Tema del gráfico
             main = "Clusters de Estados de EE. UU. (USArrests) segun criminalidad")

Discusión de resultados en contexto sociológico:

Analizar las características de los estados en cada conglomerado basándose en los centroides (tasas de arresto). Por ejemplo, si se observa el output de km.res$centers:

  • Un cluster podría tener altas tasas en todas las categorías (estados con alta criminalidad general).
  • Otro cluster podría tener bajas tasas en todas las categorías (estados con baja criminalidad).
  • Un tercer cluster podría tener tasas altas de asalto pero bajas de asesinato y violación (patrón específico).
  • Un cuarto cluster podría mostrar otro patrón distintivo.

Implicaciones para políticas públicas: ¿Cómo diseñar políticas de seguridad o programas de intervención social diferenciados para cada tipo de estado, basándose en sus patrones de criminalidad?

Comentarios

Entradas más populares de este blog

Venezuela. Entidades federales según número de municipios

Cluster jerárquico