El propósito de esta actividad es poner en práctica lo estudiado hasta ahora en el Análisis de Clusters mediante el Algoritmo de K-Medias.
Primeramente aquí se proporcionan las librerías principales que deberás considerar. De todas maneras si deseas agregar cualquier otra librería lo puedes hacer y recomendaría hacerlo de una vez dentro del siguiente chunk de código:
library(tibble)
library(dplyr)
library(factoextra)
library(plotly)
library(SMCRM)
library(caret)
library(randomForest)
library(tree)
library(knitr)
library(randomForest)
library(cluster)
library(ggplot2)
library(clustertend)
library(NbClust)
library(hopkins)
A continuación se carga la base de datos a ser analizada: ‘USArrests’ de la librería ‘spData’
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
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…
#?USArrests
df <- na.omit(USArrests)
La meta esencial del análisis que llevarás a cabo será replicar lo estudiado en el código ‘ClusterAnalysis’.
Para dar un poco de variedad a las presentaciones, cada equipo deberá utilizar la función de distancia aquí especificada y una metodología específica para determinar el número óptimo de Clusters. - Equipo 1: Distancia - Minkowski y Gap_Stat - Equipo 2: Distancia - Maximum y Silhouette - Equipo 3: Distancia - Manhattan y WSS - Equipo 4: Distancia - Pearson y Gap_Stat - Equipo 5: Distancia - Spearman y Silhouette - Equipo 6: Distancia - Kendall y WSS - Equipo 7: Distancia - Canberra y Gap_Stat
Las instrucciones específicas a seguir son las siguientes: - Escala las variables
# Escalar variables
df_scaled <- scale(df)
set.seed(123)
clust_tendency <- get_clust_tendency(df_scaled, n = 45,
gradient = list(low = "steelblue", high = "white"))
# Visualizar matriz de disimilitud
clust_tendency$plot
Muestra y analiza detalladamente el Estadístico de Hopkin
# Imprimir el estadístico de Hopkins
cat("Hopkins Statistic:", round(clust_tendency$hopkins_stat, 3), "\n")
## Hopkins Statistic: 0.606
La prueba de Hopkins aplicada sobre el conjunto de datos estandarizado arrojó un valor cercano a 0.6, lo cual sugiere una tendencia moderada hacia la formación de clústers, es decir, los datos presentan cierto grado de agrupamiento no aleatorio. La matriz de disimilitud generada permite observar patrones visuales que respaldan esta conclusión: se identifican zonas con bloques de color similares, lo que indica que algunos estados presentan perfiles de arresto parecidos. Estos hallazgos justifican continuar con la aplicación de algoritmos de segmentación como K-medias para identificar grupos naturales dentro del conjunto de estados analizados.
Muestra la gráfica asociada a esta prueba (Matriz de similitudes con la función de distancia asignada a tu equipo)
pearson_dist <- as.dist(1 - cor(t(df_scaled), method = "pearson"))
fviz_dist(pearson_dist,
order = TRUE,
show_labels = FALSE,
lab_size = NULL,
gradient = list(low = "steelblue", high = "white")) +
ggtitle("Matriz de disimilitud (distancia Pearson)")
Se puede notar que hay algunas áreas con bloques bien definidos, lo que sugiere la presencia potencial de grupos en los datos. En esta matriz, los tonos más oscuros indican mayor similitud (menor disimilitud) entre pares de estados, mientras que los tonos más claros representan estados con perfiles de arresto más distintos. Se observan ciertos bloques de color homogéneo, lo que sugiere la posible existencia de grupos de estados con patrones similares de criminalidad. Este comportamiento respalda la hipótesis de que la base de datos es apta para ser segmentada mediante técnicas de clustering.
# Usar Gap Statistic para determinar el número óptimo de clústers
set.seed(123)
gap_stat <- clusGap(df_scaled, FUN = kmeans, K.max = 10, B = 100)
# Visualizar los resultados
fviz_gap_stat(gap_stat)
# Imprimir el número óptimo de clústers
optimal_k <- which.max(gap_stat$Tab[, "gap"])
cat("Número óptimo de clústers según Gap Statistic:", optimal_k, "\n")
## Número óptimo de clústers según Gap Statistic: 4
Para determinar el número óptimo de clústers, se aplicó el método de Gap Statistic con 100 remuestreos bootstrap sobre los datos estandarizados. La gráfica obtenida muestra que el valor máximo del estadístico Gap se alcanza cuando k = 4, lo cual indica que este número de grupos logra la mejor separación entre clústers, maximizando la diferencia entre la dispersión observada y la esperada bajo una distribución aleatoria. Este resultado respalda la decisión de segmentar el conjunto de datos en cuatro conglomerados distintos, que posteriormente serán identificados mediante el algoritmo de K-medias.
# Aplicar K-means con 4 clusters
set.seed(123)
kmeans_result <- kmeans(df_scaled, centers = 4, nstart = 25)
# Agregar los clusters al dataframe original
df_clustered <- USArrests %>%
mutate(Cluster = as.factor(kmeans_result$cluster))
# Aplicar K-means con 4 clusters
set.seed(123)
kmeans_result <- kmeans(df_scaled, centers = 4, nstart = 25)
# Agregar los clusters al dataframe original
df_clustered <- USArrests %>%
mutate(Cluster = as.factor(kmeans_result$cluster))
# Revisar estructura del resultado de K-means
str(kmeans_result)
## List of 9
## $ cluster : Named int [1:50] 1 4 4 1 4 4 3 3 4 1 ...
## ..- attr(*, "names")= chr [1:50] "Alabama" "Alaska" "Arizona" "Arkansas" ...
## $ centers : num [1:4, 1:4] 1.412 -0.962 -0.489 0.695 0.874 ...
## ..- attr(*, "dimnames")=List of 2
## .. ..$ : chr [1:4] "1" "2" "3" "4"
## .. ..$ : chr [1:4] "Murder" "Assault" "UrbanPop" "Rape"
## $ totss : num 196
## $ withinss : num [1:4] 8.32 11.95 16.21 19.92
## $ tot.withinss: num 56.4
## $ betweenss : num 140
## $ size : int [1:4] 8 13 16 13
## $ iter : int 2
## $ ifault : int 0
## - attr(*, "class")= chr "kmeans"
# Confirmar que el número de clusters es 4
table(kmeans_result$cluster)
##
## 1 2 3 4
## 8 13 16 13
# Visualizar los clústers usando PCA (2D)
fviz_cluster(object = kmeans_result,
data = df_scaled,
ellipse.type = "norm", # Ellipses for cluster shape
palette = "jco",
geom = "point",
show.clust.cent = TRUE,
ggtheme = theme_minimal())
La visualización de los clústers generados mediante el algoritmo de K-medias muestra una clara segmentación de los datos en cuatro grupos bien diferenciados, con mínimas áreas de superposición. Esta representación bidimensional se obtuvo a través de un análisis de componentes principales (PCA), donde el primer componente explica el 62% de la varianza y el segundo componente un 24.7%, lo que permite capturar de manera eficiente la estructura interna del conjunto de datos. Cada clúster presenta una distribución espacial distinta, lo que sugiere que existen perfiles estadísticamente diferenciables en los patrones de arrestos entre los estados, validando así la decisión de utilizar cuatro conglomerados en el análisis.
library(plotly)
plot_ly(df_clustered,
x = ~Murder,
y = ~Assault,
z = ~Rape,
color = ~Cluster,
colors = c("blue", "gold", "gray", "red"),
type = "scatter3d",
mode = "markers") %>%
layout(title = "Clustering 3D: USArrests",
scene = list(
xaxis = list(title = "Murder"),
yaxis = list(title = "Assault"),
zaxis = list(title = "Rape")))
Para complementar el análisis visual, se generó una representación tridimensional de los clústers utilizando las variables originales del conjunto de datos: Murder, Assault y Rape. En este gráfico interactivo se observa cómo los cuatro grupos identificados mediante K-means se distribuyen en el espacio tridimensional, confirmando la segmentación previa. Se aprecia que ciertos clústers agrupan estados con niveles particularmente altos o bajos en las tres variables, mientras que otros se concentran en zonas intermedias. Esta representación permite validar visualmente que los clústers generados no sólo existen en un plano reducido (PCA), sino que también se manifiestan en las variables originales, reforzando la solidez de la clasificación obtenida.