CÁTEDRA:
MÉTODOS PARA EL ANÁLISIS ECONÓMICO
DOCENTE:
MSF. CARLOS ADEMIR PEREZ ALAS
GRUPO TEÓRICO:
01
| PRESENTADO POR: | CARNET |
| BENJAMIN ISAAC CASTANEDA SOSA | CS223038 |
Ciudad Universitaria “Dr. Fabio Castillo Figueroa”
17 de noviembre
de 2025, San Salvador, El Salvador
El Análisis de Conglomerados (Clustering) es un algoritmo de aprendizaje automático no supervisado que se utiliza para clasificar las observaciones dentro de un conjunto de datos en múltiples grupos basándose en su similitud @kassambara2017practical
El objetivo es dividir el conjunto de datos de tal manera que los objetos dentro del mismo grupo sean lo más similares posible (alta similitud intra-clase), y los objetos de grupos diferentes sean lo más disímiles posible (baja similitud inter-clase) @kassambara2017practical
Los métodos particionales son utilizados para clasificar observaciones en múltiples grupos y requieren que el analista especifique previamente el número de clústeres (k) a generar. (Kassambara, 2017, p. 34).
La agrupación no jerárquica se puede subdividir en dos tipos:
• K-means clustering: Cada clúster se representa por la media o centro de sus puntos.
• K-medoids clustering (PAM): Cada clúster se representa por uno de los objetos que realmente está en el clúster (medoide). Es menos sensible a valores atípicos.
• CLARA algorithm: Una extensión de PAM diseñada para manejar conjuntos de datos muy grandes.
(Kassambara, 2017, p. 34)
El clustering jerárquico es un enfoque alternativo al clustering particional. A diferencia de este último, no requiere que el analista especifique previamente el número de clústeres a producir. (Kassambara, 2017, p. 65).
El resultado de este análisis se representa como una estructura de árbol llamada dendrograma (Kassambara, 2017, p. 66). Esta representación permite al analista decidir a posteriori el número final de grupos cortando el árbol a una altura específica (Kassambara, 2017, p. 66).
La agrupación jerárquica se puede subdividir en dos tipos:
• Clustering Aglomerativo: Método “bottom-up” que comienza con cada objeto como su propio clúster y luego fusiona sucesivamente los clústeres más similares hasta que queda solo uno grande.
• Clustering Divisivo: Método “top-down” que comienza con un clúster grande que contiene todas las observaciones y luego lo divide sucesivamente hasta que cada observación está en su propio grupo.
(Kassambara, 2017, p. 65)
Resumen del Análisis de Clúster
| Análisis.de.Clúster | Técnicas.disponibles | Ventajas | Desventajas |
|---|---|---|---|
| Jerárquico: : Este enfoque no requiere que el analista especifique previamente el número de grupos. El resultado se muestra en un dendrograma que permite decidir cuántos clústeres cortar. |
|
|
|
| No jerárquico: Este método requiere que el analista especifique previamente el número de clústeres (k) que se desea generar. |
|
|
|
Fuente: elaboración propia con base en (Kassambara, 2017).
Los Métodos Jerárquicos de Análisis de Clúster se definen como: Un enfoque de agrupamiento que no requiere que el analista especifique previamente el número de grupos (K). Su resultado principal es un dendrograma (un diagrama en forma de árbol) que muestra la estructura anidada de los clústeres, lo que permite al analista decidir dónde “cortar” para obtener el número de grupos deseado.
Se dividen en dos tipos principales:
Comienza con cada objeto como un clúster individual y los fusiona sucesivamente.
Librería y sintaxis en R
El elemento crucial para realizar el análisis de clúster es la medición de la (des)similitud entre los objetos o grupos, lo cual determina qué elementos deben combinarse (métodos jerárquicos aglomerativos) o dividirse (métodos jerárquicos divisivos).
1. Métodos de (Des)similitud
Se utilizan diversas métricas de distancia, siendo las más comunes la distancia Euclidiana y la distancia de Manhattan.
2. Implementación en R
• El cálculo de las distancias entre cada par de objetos se realiza mediante la función dist() en el software R.
• El resultado de este cálculo es una matriz de distancia o de disimilitud.
• Por defecto, dist() utiliza la distancia Euclidiana.
Es posible especificar otras métricas de distancia utilizando el argumento method dentro de la función.
La matriz de distancias res.dist, obtenida mediante la función dist(), puede emplearse para construir un árbol de agrupamiento jerárquico utilizando la función base hclust() en R. Su uso típico es:
Fuente: elaboración propia con base en (Kassambara, 2017).
• d: matriz de disimilitudes generada por dist().
• method: método de aglomeración utilizado para calcular la distancia entre clústeres. Entre los métodos disponibles se encuentran: “ward.D”, “ward.D2”, “single”, “complete”, “average”, “mcquitty”, “median” y “centroid”.
Existen diversos métodos de enlace para formar clústeres, cada uno con características propias; los más utilizados se describen en la sección correspondiente.
Estructura en R
# Cargar Data
data("USArrests")
# Estandarizar la Data
df <- scale(USArrests)
# Calcular Matriz de distancia
res.dist <- dist(df, method = "euclidean")
# Convertir como matriz
as.matrix(res.dist)[1:6, 1:6]
# Tecnicas de aglomeracion jerarquica
res.hc <- hclust(d = res.dist, method = "ward.D") #Minimiza la varianza total intragrupo.
res.hc <- hclust(d = res.dist, method = "ward.D2") #Minimiza la varianza total intragrupo.
res.hc <- hclust(d = res.dist, method = "single") #Mínima distancia entre todos los elementos.
res.hc <- hclust(d = res.dist, method = "complete") #Máxima distancia entre todos los elementos.
res.hc <- hclust(d = res.dist, method = "avarage") #Calcula el promedio de todas las distancias.
res.hc <- hclust(d = res.dist, method = "median") #Distancia entre medianas.
res.hc <- hclust(d = res.dist, method = "centroid") #Mide distancia entre los centroides.Fuente: elaboración propia con base en (Kassambara, 2017).
Técnicas Disponibles Especificadas
• Enlace máximo o completo:
La distancia entre dos conglomerados se define como el valor máximo de todas las distancias por pares entre los elementos del conglomerado 1 y los elementos del conglomerado 2. Tiende a producir conglomerados más compactos.
• Enlace mínimo o único
La distancia entre dos clústeres se define como el valor mínimo de todas las distancias por pares entre los elementos del clúster 1 y los elementos del clúster 2. Tiende a producir clústeres largos y “flojos”.
• Enlace medio o promedio
La distancia entre dos conglomerados se define como la distancia promedio entre los elementos del conglomerado 1 y los elementos del conglomerado 2.
• Enlace del centróide
La distancia entre dos clústeres se define como la distancia entre el centróide del clúster 1 (un vector medio de longitud p variables) y el centróide del clúster 2.
• Método de la mediana
Parecido al centroide, pero los clústeres se representan por su mediana en cada variable, lo que lo hace más robusto a valores extremos.
• Método de varianza mínima de Ward
Minimiza la varianza total dentro del clúster. En cada paso, se fusiona el par de clústeres con la distancia mínima entre clústeres.
res.hc <- hclust(d = res.dist, method = "ward.D") #Minimiza la varianza total intragrupo.
res.hc <- hclust(d = res.dist, method = "ward.D2") #Minimiza la varianza total intragrupo.Fuente: elaboración propia con base en (Kassambara, 2017).
Comienza con todos los objetos en un único clúster y lo divide sucesivamente.
Estructura en R
El paquete de R ‘cluster’ facilita la realización de análisis de conglomerados en R. Proporciona la funcion diana() para calcular conglomerados de manera aglomerativa y divisiva, respectivamente. Estas funciones realizan todos los pasos necesarios por ti. No necesitas ejecutar las funciones scale(), dist() y hclust() por separado. Las funciones se pueden ejecutar de la siguiente manera:
# DIvisive ANAlysis Clustering
res.diana <- diana(x = USArrests, # matriz de datos
stand = TRUE, # Estandarizar los datos
metric = "euclidean" # Métrica para matriz de distancias
)Fuente: elaboración propia con base en (Kassambara, 2017).
Después de ejecutar diana(), puedes usar la función fviz_dend()[en factoextra] para visualizar el resultado:
Los Métodos No Jerárquicos de Análisis de Clúster son: Un enfoque de agrupamiento que requiere que el analista especifique previamente el número de clústeres (K) que se desea generar.
Buscan la partición óptima de los datos en ese número fijo de grupos (K).
Los métodos clave en esta categoría son:
• K-means: Representado por el centroide (la media).
• K-medoids (PAM): Representado por el medoide (un punto de dato real).
• CLARA: Una extensión de PAM para manejar datos muy grandes.
Librería y sintaxis en R
El Clustering K-means (MacQueen, 1967) es el algoritmo de aprendizaje automático no supervisado más común dentro de los métodos no jerárquicos o particionales. Su propósito principal es dividir un conjunto de datos en un número K de grupos que debe ser preespecificado por el analista. Este método busca crear una partición única y óptima de los datos.
El principio fundamental de K-means es la segregación de objetos para maximizar la similitud intra-clase (que los objetos dentro del mismo grupo sean lo más parecidos posible) y, simultáneamente, minimizar la similitud inter-clase (que los objetos de diferentes grupos sean lo más disímiles posible). Para lograr esta clasificación, cada clúster está representado por su centroide, el cual corresponde al vector de la media de todos los puntos que han sido asignados a ese clúster.
kmeans(x, centers, iter.max = 10, nstart = 1)
# Compute k-means with k = 4
set.seed(123) # Usar set.seed() antes de K-means garantiza resultados idénticos y reproducibles al fijar el generador aleatorio de R.
km.res <- kmeans(df, 4, nstart = 25)Fuente: elaboración propia con base en (Kassambara, 2017).
• x: matriz numérica, marco de datos numérico o un vector numérico
• centers: Los valores posibles son el número de clústeres (k) o un conjunto de centros de clúster iniciales (distintos). Si es un número, se selecciona un conjunto aleatorio de filas (distintas) en x como los centros iniciales.
• iter.max: El número máximo de iteraciones permitidas. El valor predeterminado es 10.
• nstart: El número de particiones iniciales aleatorias cuando centers es un número. A menudo se recomienda probar con nstart > 1.
(Kassambara, 2017, p 39)
El algoritmo K-medoids es una técnica de clustering que se relaciona directamente con K-means, ya que también es un método particional que requiere que el analista especifique previamente el número de clústeres (K). Su característica distintiva es que cada grupo está representado por un medoide. Este medoide es, de hecho, un punto de dato real dentro del clúster que se encuentra en la ubicación más central, pues minimiza la disimilitud promedio con todos los demás miembros del grupo (Kassambara, 2017, p 48).
La principal ventaja de K-medoids es su robustez en comparación con K-means. Al utilizar medoides (puntos de datos reales) en lugar de centroides (valores promedio calculados), el algoritmo es menos sensible al ruido y a los valores atípicos (outliers). El método más común para implementar esta técnica es el algoritmo PAM (Partitioning Around Medoids).
La función pam() [paquete cluster] y pamk() [paquete fpc] se pueden usar para calcular PAM. La función pamk() no requiere que el usuario decida el número de clusters K. En los siguientes ejemplos, describiremos solo la función pam(), cuyo formato simplificado es:
pam(x, k, metric = "euclidean", stand = FALSE)
# The R code below computes PAM algorithm with k = 2:
pam.res <- pam(df, 2)
print(pam.res)Fuente: elaboración propia con base en (Kassambara, 2017).
• x: los valores posibles incluyen:
Matriz de datos numéricos o data frame numérico: cada fila corresponde a una observación, y cada columna corresponde a una variable.
Matriz de disimilitud: en este caso, x suele ser la salida de daisy() o dist()
• k: el número de clusters • metric: las métricas de distancia a utilizar. Las opciones disponibles son “euclidiana” y “manhattan”.
• stand: valor lógico; si es verdadero, las variables (columnas) en x se estandarizan antes de calcular las disimilitudes. Se ignora cuando x es una matriz de disimilitud.
(Kassambara, 2017, p 51).
El algoritmo CLARA (Clustering Large Applications), propuesto por Kaufman y Rousseeuw (1990), es una extensión del método K-medoids (PAM). Su principal función es manejar eficientemente conjuntos de datos que contienen un gran número de objetos (más de varios miles de observaciones), ya que reduce significativamente el tiempo de cómputo y los problemas de almacenamiento en RAM (Kassambara, 2017, p 57).
Para lograr esta optimización, CLARA implementa un enfoque de muestreo. En lugar de buscar los medoides en la totalidad del conjunto de datos, el algoritmo toma una pequeña muestra de los datos (de tamaño fijo, sampsize) y aplica el algoritmo PAM únicamente a esta muestra (Kassambara, 2017, p 57)..
La función clara() [paquete cluster] se puede usar para calcular CLARA. El formato simplificado es el siguiente:
clara(x, k, metric = "euclidean", stand = FALSE,
samples = 5, pamLike = FALSE)
#The R code below computes PAM algorithm with k = 2:
# Compute CLARA
clara.res <- clara(df, 2, samples = 50, pamLike = TRUE)
# Print components of clara.res
print(clara.res)Fuente: elaboración propia con base en (Kassambara, 2017).
• x: una matriz de datos numéricos o un data frame, cada fila corresponde a una observación y cada columna corresponde a una variable. Se permiten valores faltantes (NA).
• k: el número de clústeres.
• métrica: las métricas de distancia que se utilizarán. Las opciones disponibles son “euclidiana” y “manhattan”. Las distancias euclidianas son la raíz de la suma de los cuadrados de las diferencias, y las distancias de Manhattan son la suma de las diferencias absolutas. Tenga en cuenta que la distancia de Manhattan es menos sensible a los valores atípicos.
• stand: valor lógico; si es verdadero, las variables (columnas) en x se estandarizan antes de calcular las disimilitudes. Cabe señalar que se recomienda estandarizar las variables antes de la agrupación.
• samples: número de muestras que se extraerán del conjunto de datos. El valor predeterminado es 5, pero se recomienda un valor mucho mayor.
• pamLike: valor lógico que indica si se debe usar el mismo algoritmo que en la función pam(). Esto siempre debe ser verdadero.
(Kassambara, 2017, p 5).
Data
Antes de aplicar K-means, se debe preparar el conjunto de datos “USArrests”. Como el algoritmo usa medias, se requiere que los datos sean variables continuas únicamente. Es fundamental escalar los datos usando la función scale() de R para eliminar el efecto de las unidades arbitrarias de las variables y asegurar que todas contribuyan por igual
data("USArrests") # Loading the data set
df <- scale(USArrests) # Scaling the data
# View the firt 3 rows of the data
head(df, n = 3)## Murder Assault UrbanPop Rape
## Alabama 1.24256408 0.7828393 -0.5209066 -0.003416473
## Alaska 0.50786248 1.1068225 -1.2117642 2.484202941
## Arizona 0.07163341 1.4788032 0.9989801 1.042878388
Estimación del Número Óptimo de Clústeres (K)
Dado que K-means requiere pre-especificar K, se utiliza el Método del Codo (Elbow Method). Este método calcula el WSS (varianza intraclúster) para diferentes valores de K, graficándolo luego para identificar un “codo” donde la disminución marginal del WSS se estabiliza. Este punto indica el valor de K más apropiado, y se puede implementar convenientemente en R con la función fviz_nbclust() del paquete factoextra.
## Cargando paquete requerido: ggplot2
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
Al observar el gráfico de varianza intraclúster (WSS), se identifica un “codo” o punto de inflexión en el valor de K=4. Esto significa que añadir clústeres más allá del cuarto ofrece una ganancia marginal muy pequeña en la reducción de la varianza. Por lo tanto, el número óptimo de clústeres se establece en K=4, y la clasificación de las observaciones se realizará con esta partición.
Cálculo del Clúster K-means en R
El algoritmo K-means inicia con centroides aleatorios, por lo que se usa set.seed() para garantizar la reproducibilidad de los resultados. Además, para asegurar la estabilidad del clúster, se especifica nstart = 25. Esto fuerza a R a probar 25 inicios diferentes y seleccionar la solución con la menor variación interna. El código implementa este método con la partición óptima de K=4 clústeres.
# Compute k-means with k = 4
set.seed(123)
km.res <- kmeans(df, 4, nstart = 25)
# Print the results
print(km.res)## K-means clustering with 4 clusters of sizes 8, 13, 16, 13
##
## Cluster means:
## Murder Assault UrbanPop Rape
## 1 1.4118898 0.8743346 -0.8145211 0.01927104
## 2 -0.9615407 -1.1066010 -0.9301069 -0.96676331
## 3 -0.4894375 -0.3826001 0.5758298 -0.26165379
## 4 0.6950701 1.0394414 0.7226370 1.27693964
##
## Clustering vector:
## Alabama Alaska Arizona Arkansas California
## 1 4 4 1 4
## Colorado Connecticut Delaware Florida Georgia
## 4 3 3 4 1
## Hawaii Idaho Illinois Indiana Iowa
## 3 2 4 3 2
## Kansas Kentucky Louisiana Maine Maryland
## 3 2 1 2 4
## Massachusetts Michigan Minnesota Mississippi Missouri
## 3 4 2 1 4
## Montana Nebraska Nevada New Hampshire New Jersey
## 2 2 4 2 3
## New Mexico New York North Carolina North Dakota Ohio
## 4 4 1 2 3
## Oklahoma Oregon Pennsylvania Rhode Island South Carolina
## 3 3 3 3 1
## South Dakota Tennessee Texas Utah Vermont
## 2 1 4 3 2
## Virginia Washington West Virginia Wisconsin Wyoming
## 3 3 2 2 3
##
## Within cluster sum of squares by cluster:
## [1] 8.316061 11.952463 16.212213 19.922437
## (between_SS / total_SS = 71.2 %)
##
## Available components:
##
## [1] "cluster" "centers" "totss" "withinss" "tot.withinss"
## [6] "betweenss" "size" "iter" "ifault"
Interpretación de la Salida de K-means
El resultado impreso del algoritmo K-means proporciona dos elementos de salida fundamentales para el análisis: primero, la matriz de Medias o Centros del Clúster, la cual detalla el valor promedio de cada variable dentro de cada uno de los clústeres formados, sirviendo para caracterizar y nombrar los grupos; y segundo, el Vector de Clustering, que es una asignación de enteros indicando con precisión a qué clúster final ha sido asociado cada punto u observación individual del conjunto de datos.
Es posible calcular la media de cada variable por clústeres usando los datos originales:
## cluster Murder Assault UrbanPop Rape
## 1 1 13.93750 243.62500 53.75000 21.41250
## 2 2 3.60000 78.53846 52.07692 12.17692
## 3 3 5.65625 138.87500 73.87500 18.78125
## 4 4 10.81538 257.38462 76.00000 33.19231
Si quieres agregar las clasificaciones de puntos a los datos originales, usa esto:
## Murder Assault UrbanPop Rape cluster
## Alabama 13.2 236 58 21.2 1
## Alaska 10.0 263 48 44.5 4
## Arizona 8.1 294 80 31.0 4
## Arkansas 8.8 190 50 19.5 1
## California 9.0 276 91 40.6 4
## Colorado 7.9 204 78 38.7 4
Accediendo a los resultados de la función kmeans()
Accediento al número de clúster para cada una de las observaciones
Accediendo al tamaño de cada clúster
## [1] 8 13 16 13
Accediendo a la matriz de centros de clúster (medias de clúster)
## Murder Assault UrbanPop Rape
## 1 1.4118898 0.8743346 -0.8145211 0.01927104
## 2 -0.9615407 -1.1066010 -0.9301069 -0.96676331
## 3 -0.4894375 -0.3826001 0.5758298 -0.26165379
## 4 0.6950701 1.0394414 0.7226370 1.27693964
Visualizando los clústeres de k-means
Para visualizar la separación de clústeres cuando hay muchas variables, se aplica PCA (Análisis de Componentes Principales). Esta técnica reduce la dimensionalidad a dos componentes, permitiendo un gráfico de dispersión 2D donde los puntos se colorean según su clúster. La función fviz_cluster() facilita esta interpretación visual sobre el plano PCA.
fviz_cluster(km.res, data = df,
palette = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
ellipse.type = "euclid", # Concentration ellipse
star.plot = TRUE, # Add segments from centroids to items
repel = TRUE, # Avoid label overplotting (slow)
ggtheme = theme_minimal()
)Datos
Usaremos los conjuntos de datos de demostración “USArrests”, que comenzamos escalando (Capítulo 4) usando la función scale() de R de la siguiente manera:
data("USArrests") # Load the data set
df <- scale(USArrests) # Scale the data
head(df, n = 3) # View the firt 3 rows of the data## Murder Assault UrbanPop Rape
## Alabama 1.24256408 0.7828393 -0.5209066 -0.003416473
## Alaska 0.50786248 1.1068225 -1.2117642 2.484202941
## Arizona 0.07163341 1.4788032 0.9989801 1.042878388
Estimación de K con el Método Silhouette
Para determinar el número óptimo de clústeres (K) para el algoritmo PAM (K-medoids), se emplea el Método de la Silueta Promedio. Esta técnica calcula la anchura de la silueta promedio para un rango de valores de K, una métrica que evalúa la calidad de la separación de los clústeres. El valor óptimo de K es aquel que maximiza esta silueta promedio, indicando la mejor partición posible de los datos (Kaufman y Rousseeuw, 1990). La función fviz_nbclust() del paquete factoextra facilita la implementación de este método en R (Kassambara, 2017, p. 52).
Según el gráfico, el número sugerido de clústeres es 2. En la siguiente sección, clasificaremos las observaciones en 2 clústeres.
Cálculo de la agrupación PAM
El código R a continuación calcula el algoritmo PAM con k = 2:
## Medoids:
## ID Murder Assault UrbanPop Rape
## New Mexico 31 0.8292944 1.3708088 0.3081225 1.1603196
## Nebraska 27 -0.8008247 -0.8250772 -0.2445636 -0.5052109
## Clustering vector:
## Alabama Alaska Arizona Arkansas California
## 1 1 1 2 1
## Colorado Connecticut Delaware Florida Georgia
## 1 2 2 1 1
## 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
## 2 1 2 1 1
## Montana Nebraska Nevada New Hampshire New Jersey
## 2 2 1 2 2
## New Mexico New York North Carolina North Dakota Ohio
## 1 1 1 2 2
## Oklahoma Oregon Pennsylvania Rhode Island South Carolina
## 2 2 2 2 1
## South Dakota Tennessee Texas Utah Vermont
## 2 1 1 2 2
## Virginia Washington West Virginia Wisconsin Wyoming
## 2 2 2 2 2
## Objective function:
## build swap
## 1.441358 1.368969
##
## Available components:
## [1] "medoids" "id.med" "clustering" "objective" "isolation"
## [6] "clusinfo" "silinfo" "diss" "call" "data"
La salida impresa muestra:
• Los medoid de los grupos: una matriz, cuyas filas son los medoid y las columnas son las variables
• El vector de clúster: un vector de enteros (de 1 a k) que indica el clúster al que se asigna cada punto
Si quieres agregar las clasificaciones de puntos a los datos originales, usa esto:
## Murder Assault UrbanPop Rape cluster
## Alabama 13.2 236 58 21.2 1
## Alaska 10.0 263 48 44.5 1
## Arizona 8.1 294 80 31.0 1
Accediendo a los resultados de la función pam()
Accediendo a los medoides (Objetos que representan clústeres)
## Murder Assault UrbanPop Rape
## New Mexico 0.8292944 1.3708088 0.3081225 1.1603196
## Nebraska -0.8008247 -0.8250772 -0.2445636 -0.5052109
Accediento al número de clúster para cada una de las observaciones
## Alabama Alaska Arizona Arkansas California Colorado
## 1 1 1 2 1 1
Visualizando clústeres PAM
Para visualizar los resultados de la partición (clustering), se utiliza la función fviz_cluster() (del paquete factoextra). Esta función genera un gráfico de dispersión con los puntos coloreados según su asignación de clúster. Cuando el conjunto de datos tiene más de dos variables, se aplica automáticamente el Análisis de Componentes Principales (PCA). Esto reduce la dimensionalidad para que los datos puedan ser graficados utilizando sus dos primeras componentes principales (Kassambara, 2017, p. 66).
fviz_cluster(pam.res,
palette = c("#00AFBB", "#FC4E07"), # color palette
ellipse.type = "t", # Concentration ellipse
repel = TRUE, # Avoid label overplotting (slow)
ggtheme = theme_classic()
)Formato y preparación de datos
Para calcular el algoritmo CLARA en R, los datos deben prepararse como se indica en el Capítulo 2. Aquí, utilizaremos un conjunto de datos aleatorio. Para hacer que el resultado sea reproducible, comenzamos usando la función set.seed().
set.seed(1234)
# Generate 500 objects, divided into 2 clusters.
df <- rbind(cbind(rnorm(200,0,8), rnorm(200,0,8)),
cbind(rnorm(300,50,8), rnorm(300,50,8)))
# Specify column and row names
colnames(df) <- c("x", "y")
rownames(df) <- paste0("S", 1:nrow(df))
# Previewing the data
head(df, nrow = 6)## x y
## S1 -9.656526 3.881815
## S2 2.219434 5.574150
## S3 8.675529 1.484111
## S4 -18.765582 5.605868
## S5 3.432998 2.493448
## S6 4.048447 6.083699
Estimación del número óptimo de clústeres
Para estimar el número óptimo de clústeres en tus datos, es posible usar el método del silueta promedio como se describe en el capítulo de clustering PAM (Capítulo 5). La función de R fviz_nbclust() [paquete factoextra] ofrece una solución para facilitar este paso.
library(cluster)
library(factoextra)
fviz_nbclust(df, clara, method = "silhouette")+
theme_classic()A partir del gráfico, el número sugerido de clústeres es 2. En la siguiente sección, clasificaremos las observaciones en 2 clústeres.
Computando CLARA
El código R a continuación calcula el algoritmo PAM con k = 2:
# Compute CLARA
clara.res <- clara(df, 2, samples = 50, pamLike = TRUE)
# Print components of clara.res
print(clara.res)## Call: clara(x = df, k = 2, samples = 50, pamLike = TRUE)
## Medoids:
## x y
## S121 -1.531137 1.145057
## S455 48.357304 50.233499
## Objective function: 9.87862
## Clustering vector: Named int [1:500] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ...
## - attr(*, "names")= chr [1:500] "S1" "S2" "S3" "S4" "S5" "S6" "S7" ...
## Cluster sizes: 200 300
## Best sample:
## [1] S37 S49 S54 S63 S68 S71 S76 S80 S82 S101 S103 S108 S109 S118 S121
## [16] S128 S132 S138 S144 S162 S203 S210 S216 S231 S234 S249 S260 S261 S286 S299
## [31] S304 S305 S312 S315 S322 S350 S403 S450 S454 S455 S456 S465 S488 S497
##
## Available components:
## [1] "sample" "medoids" "i.med" "clustering" "objective"
## [6] "clusinfo" "diss" "call" "silinfo" "data"
La salida de la función clara() incluye los siguientes componentes:
• medoids: Objetos que representan los clústeres.
• clustering: Un vector que contiene el número de clúster de cada objeto.
• sample: Etiquetas o números de caso de las observaciones en la mejor muestra, es decir, la muestra utilizada por el algoritmo clara para la partición final.
Si quieres agregar las clasificaciones de puntos a los datos originales, usa esto:
## x y cluster
## S1 -9.656526 3.881815 1
## S2 2.219434 5.574150 1
## S3 8.675529 1.484111 1
## S4 -18.765582 5.605868 1
Puedes acceder a los resultados devueltos por clara() de la siguiente manera:
## x y
## S121 -1.531137 1.145057
## S455 48.357304 50.233499
## S1 S2 S3 S4 S5 S6 S7 S8 S9 S10
## 1 1 1 1 1 1 1 1 1 1
The medoids are S121, S455
Visualizando los clústeres CLARA
Para visualizar los resultados de la partición, utilizaremos la función fviz_cluster() [paquete factoextra]. Esta dibuja un diagrama de dispersión de los puntos de datos coloreados según los números de clúster
fviz_cluster(clara.res,
palette = c("#00AFBB", "#FC4E07"), # color palette
ellipse.type = "t", # Concentration ellipse
geom = "point", pointsize = 1,
ggtheme = theme_classic()
)Estructura y preparación de datos
La estructura de los datos para el clustering debe ser una matriz numérica donde las filas representan las observaciones (individuos) y las columnas representan las variables.
Antes de realizar el análisis jerárquico, es fundamental estandarizar las variables (por ejemplo, usando la función scale() de R). La estandarización es esencial cuando las variables se miden en diferentes escalas (ej. metros vs. kilogramos), haciendo que sean comparables y que ninguna variable domine el cálculo de distancias arbitrariamente. Para este informe, se utiliza el conjunto de datos base de R USArrests.
# Load the data
data("USArrests")
# Standardize the data
df <- scale(USArrests)
# Show the first 6 rows
head(df, nrow = 6)## Murder Assault UrbanPop Rape
## Alabama 1.24256408 0.7828393 -0.5209066 -0.003416473
## Alaska 0.50786248 1.1068225 -1.2117642 2.484202941
## Arizona 0.07163341 1.4788032 0.9989801 1.042878388
## Arkansas 0.23234938 0.2308680 -1.0735927 -0.184916602
## California 0.27826823 1.2628144 1.7589234 2.067820292
## Colorado 0.02571456 0.3988593 0.8608085 1.864967207
Medidas de Similitud (Distancia)
Para determinar qué objetos o clústeres deben combinarse o dividirse, el análisis de clúster se basa en medir la (des)similitud entre ellos. Existen diversas métricas para este cálculo, siendo las más comunes las distancias Euclidiana y de Manhattan.
En el software R, la función dist() se utiliza para calcular la distancia entre cada par de objetos en el conjunto de datos, generando una matriz de distancia o disimilitud. Por defecto, dist() calcula la distancia Euclidiana, pero permite especificar otras métricas mediante el argumento method.
# Compute the dissimilarity matrix
# df = the standardized data
res.dist <- dist(df, method = "euclidean")La función dist() de R calcula la distancia entre las filas de la matriz de datos, donde cada fila representa una observación o individuo.
El resultado de dist() es reformateado con as.matrix() para obtener la Matriz de Distancia tradicional. En esta matriz, el valor en la celda formada por la fila i y la columna j representa la distancia entre el objeto i y el objeto j del conjunto de datos original. Por ejemplo, la distancia entre un objeto y sí mismo (elemento i,i) siempre es cero.
El código R a continuación muestra las primeras 6 filas y columnas de la matriz de distancias:
## Alabama Alaska Arizona Arkansas California Colorado
## Alabama 0.000000 2.703754 2.293520 1.289810 3.263110 2.651067
## Alaska 2.703754 0.000000 2.700643 2.826039 3.012541 2.326519
## Arizona 2.293520 2.700643 0.000000 2.717758 1.310484 1.365031
## Arkansas 1.289810 2.826039 2.717758 0.000000 3.763641 2.831051
## California 3.263110 3.012541 1.310484 3.763641 0.000000 1.287619
## Colorado 2.651067 2.326519 1.365031 2.831051 1.287619 0.000000
Función de Enlace (Linkage) en Clúster Jerárquico
La función de Enlace (Linkage) toma como entrada la matriz de distancia generada por dist(). Su objetivo es agrupar pares de objetos o clústeres basándose en la similitud definida, repitiendo este proceso de fusión hasta que todos los objetos están unidos en una estructura jerárquica de árbol.
En R, la función base hclust() es la encargada de realizar esta vinculación y crear el árbol jerárquico.
• d: una estructura de disimilitud tal como la produce la función dist().
• method: El método de aglomeración (vinculación) que se utilizará para calcular la distancia entre clústeres. Los valores permitidos son “ward.D”, “ward.D2”, “single”, “complete”, “average”, “mcquitty”, “median” o “centroid”.
En general se prefieren la vinculación completa y el método de Ward.
Dendrograma: Representación Gráfica
El Dendrograma es la representación gráfica del árbol jerárquico generado por la función hclust(). Este diagrama visualiza cómo se agruparon progresivamente los objetos.
Aunque la función base de R plot() puede generar el dendrograma, se recomienda usar la función fviz_dend() (del paquete factoextra) para obtener una visualización más estética y detallada.
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation idioms with `aes()`.
## ℹ See also `vignette("ggplot2-in-packages")` for more information.
## ℹ The deprecated feature was likely used in the factoextra package.
## Please report the issue at <https://github.com/kassambara/factoextra/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## ℹ The deprecated feature was likely used in the factoextra package.
## Please report the issue at <https://github.com/kassambara/factoextra/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.
## ℹ The deprecated feature was likely used in the factoextra package.
## Please report the issue at <https://github.com/kassambara/factoextra/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
El dendrograma representa el árbol jerárquico donde cada hoja corresponde a una observación individual. Al ascender en el árbol, los objetos o ramas más similares se fusionan. La clave interpretativa reside en el eje vertical (la altura), que indica la distancia o disimilitud entre los objetos/clústeres fusionados. Cuanto mayor es la altura de fusión, menos similares son los elementos. Esta altura se conoce como la distancia cofenética.
Para identificar los subgrupos finales, el dendrograma debe cortarse a una altura específica. Es importante notar que la similitud se mide solo por la altura de fusión; la proximidad horizontal de las hojas no indica su similitud.
Verificación del Árbol de Clúster
Para validar la calidad del árbol jerárquico (hclust), se evalúa si sus alturas reflejan las distancias originales de los datos. Esto se logra calculando la correlación entre las distancias cofenéticas (distancias implícitas en el árbol, obtenidas con cophenetic()) y las distancias originales (dist()). Una correlación fuerte (cercana a 1, idealmente > 0.75) confirma que el clustering representa con alta precisión la estructura de los datos.
# Compute cophentic distance
res.coph <- cophenetic(res.hc)
# Correlation between cophenetic distance and
# the original distance
cor(res.dist, res.coph)## [1] 0.6975266
Ejecute la función hclust() nuevamente usando el método de enlace promedio. A continuación, llame a cophenetic() para evaluar la solución de clustering.
## [1] 0.7180382
El coeficiente de correlación muestra que usar un método de enlace diferente crea un árbol que representa las distancias originales un poco mejor.
Corte del Dendrograma para Formar Clústeres
Una limitación inherente del clustering jerárquico es que no determina automáticamente cuántos clústeres deben formarse o dónde cortar el dendrograma. Para obtener la partición final de los datos en grupos, se debe cortar el árbol jerárquico; para ello, la función base de R cutree() se aplica al árbol generado por hclust(). Este corte se puede definir especificando el número deseado de grupos (K) o indicando una altura de corte específica, devolviendo como resultado un vector que asigna cada observación a su clúster final.
## Alabama Alaska Arizona Arkansas
## 1 2 2 3
## grp
## 1 2 3 4
## 7 12 19 12
## [1] "Alabama" "Georgia" "Louisiana" "Mississippi"
## [5] "North Carolina" "South Carolina" "Tennessee"
El resultado de los cortes se puede visualizar fácilmente usando la función fviz_dend() [en factoextra]:
# Cut in 4 groups and color by groups
fviz_dend(res.hc, k = 4, # Cut in four groups
cex = 0.5, # label size
k_colors = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
color_labels_by_k = TRUE, # color labels by groups
rect = TRUE # Add rectangle around groups
)Usando la función fviz_cluster() [en factoextra], también podemos visualizar el resultado en un diagrama de dispersión. Las observaciones se representan mediante puntos en el diagrama, utilizando componentes principales. Se dibuja un marco alrededor de cada grupo.
fviz_cluster(list(data = df, cluster = grp),
palette = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
ellipse.type = "convex", # Concentration ellipse
repel = TRUE, # Avoid label overplotting (slow)
show.clust.cent = FALSE, ggtheme = theme_minimal())Paquete cluster para Análisis Jerárquico
El paquete cluster de R simplifica significativamente la ejecución del análisis de clúster jerárquico, ya que proporciona dos funciones que automatizan todos los pasos de la agrupación (escalado, cálculo de distancia y vinculación): agnes() para el clustering Aglomerativo y diana() para el clustering Divisivo. Al utilizar estas funciones, se evita la necesidad de ejecutar por separado las funciones base de R como scale(), dist() y hclust().
library("cluster")
# Agglomerative Nesting (Hierarchical Clustering)
res.agnes <- agnes(x = USArrests, # data matrix
stand = TRUE, # Standardize the data
metric = "euclidean", # metric for distance matrix
method = "ward" # Linkage method
)
# DIvisive ANAlysis Clustering
res.diana <- diana(x = USArrests, # data matrix
stand = TRUE, # standardize the data
metric = "euclidean" # metric for distance matrix
)Después de ejecutar agnes() y diana(), puedes usar la función fviz_dend()[en factoextra] para visualizar el resultado:
Preparación de datos
Usaremos los conjuntos de datos USArrests de R base y comenzamos estandarizando las variables usando la función scale() de la siguiente manera:
Para hacer que los gráficos generados en las siguientes secciones sean legibles, trabajaremos con un pequeño subconjunto aleatorio del conjunto de datos. Por lo tanto, utilizaremos la función sample() para seleccionar aleatoriamente 10 observaciones entre las 50 observaciones contenidas en el conjunto de datos:
Comparando dendrogramas
Comenzamos creando una lista de dos dendrogramas mediante el cálculo de agrupamiento jerárquico (HC) usando dos métodos de enlace diferentes (“average” y “ward.D2”). Luego, transformamos los resultados en dendrogramas y creamos una lista para contener los dos dendrogramas.
##
## ---------------------
## Welcome to dendextend version 1.19.1
## Type citation('dendextend') for how to cite the package.
##
## Type browseVignettes(package = 'dendextend') for the package vignette.
## The github page is: https://github.com/talgalili/dendextend/
##
## Suggestions and bug-reports can be submitted at: https://github.com/talgalili/dendextend/issues
## You may ask questions at stackoverflow, use the r and dendextend tags:
## https://stackoverflow.com/questions/tagged/dendextend
##
## To suppress this message use: suppressPackageStartupMessages(library(dendextend))
## ---------------------
##
## Adjuntando el paquete: 'dendextend'
## The following object is masked from 'package:stats':
##
## cutree
# Compute distance matrix
res.dist <- dist(df, method = "euclidean")
# Compute 2 hierarchical clusterings
hc1 <- hclust(res.dist, method = "average")
hc2 <- hclust(res.dist, method = "ward.D2")
# Create two dendrograms
dend1 <- as.dendrogram (hc1)
dend2 <- as.dendrogram (hc2)
# Create a list to hold dendrograms
dend_list <- dendlist(dend1, dend2)Comparación visual de dos dendrogramas
Para comparar visualmente dos dendrogramas, utilizaremos la función tanglegram() [paquete dendextend], que dibuja los dos dendrogramas lado a lado, con sus etiquetas conectadas por líneas.
La calidad de la alineación de los dos árboles se puede medir utilizando la función entanglement(). El enredamiento es una medida que varía entre 1 (enredo completo) y 0 (sin enredo). Un coeficiente de enredamiento más bajo corresponde a una buena alineación.
• Dibuja un tanglegram:
## Loading required namespace: colorspace
• Personalicé el tanglegram utilizando muchas otras opciones como las siguientes:
tanglegram(dend1, dend2,
highlight_distinct_edges = FALSE, # Turn-off dashed lines
common_subtrees_color_lines = FALSE, # Turn-off line colors
common_subtrees_color_branches = TRUE, # Color common branches
main = paste("entanglement =", round(entanglement(dend_list), 2))
)Tenga en cuenta que los nodos “únicos”, con una combinación de etiquetas/elementos que no está presente en el otro árbol, se resaltan con líneas discontinuas.
Matriz de correlación entre una lista de dendrogramas
La función cor.dendlist() se utiliza para calcular la matriz de correlación “Baker” o “Cophenética” entre una lista de árboles. El valor puede variar entre -1 y 1, siendo los valores cercanos a 0 indicativos de que los dos árboles no son estadísticamente similares.
## [,1] [,2]
## [1,] 1.0000000 0.9925544
## [2,] 0.9925544 1.0000000
## [,1] [,2]
## [1,] 1.0000000 0.9895528
## [2,] 0.9895528 1.0000000
## [1] 0.9925544
## [1] 0.9895528
También es posible comparar simultáneamente múltiples dendrogramas. Se utiliza un operador de encadenamiento %>% para ejecutar varias funciones al mismo tiempo. Es útil para simplificar el código:
# Create multiple dendrograms by chaining
dend1 <- df %>% dist %>% hclust("complete") %>% as.dendrogram
dend2 <- df %>% dist %>% hclust("single") %>% as.dendrogram
dend3 <- df %>% dist %>% hclust("average") %>% as.dendrogram
dend4 <- df %>% dist %>% hclust("centroid") %>% as.dendrogram
# Compute correlation matrix
dend_list <- dendlist("Complete" = dend1, "Single" = dend2,
"Average" = dend3, "Centroid" = dend4)
cors <- cor.dendlist(dend_list)
# Print correlation matrix
round(cors, 2)## Complete Single Average Centroid
## Complete 1.00 0.46 0.45 0.30
## Single 0.46 1.00 0.23 0.17
## Average 0.45 0.23 1.00 0.31
## Centroid 0.30 0.17 0.31 1.00
## corrplot 0.95 loaded
Como se describe en capítulos anteriores, un dendrograma es una representación basada en un árbol de un conjunto de datos creada utilizando métodos de agrupamiento jerárquico (Capítulo 7). En este artículo, proporcionamos código en R para visualizar y personalizar dendrogramas. Además, mostramos cómo guardar y hacer zoom en un dendrograma grande.
Comenzamos calculando el agrupamiento jerárquico usando los conjuntos de datos USArrests:
# Load data
data(USArrests)
# Compute distances and hierarchical clustering
dd <- dist(scale(USArrests), method = "euclidean")
hc <- hclust(dd, method = "ward.D2")Usaremos la función fviz_dend()[del paquete factoextra de R] para crear fácilmente un hermoso dendrograma utilizando ya sea el gráfico base de R o ggplot2. También ofrece una opción para dibujar dendrogramas circulares y árboles tipo filogenia.
Para crear un dendrograma básico, escribe esto:
Puedes usar los argumentos main, sub, xlab, ylab para cambiar los títulos del gráfico de la siguiente manera:
fviz_dend(hc, cex = 0.5,
main = "Dendrogram - ward.D2",
xlab = "Objects", ylab = "Distance", sub = "")Para dibujar un dendrograma horizontal, escribe esto:
También es posible cortar el árbol a una altura determinada para dividir los datos en varios grupos como se describe en el capítulo anterior: Agrupamiento jerárquico (Capítulo 7). En este caso, es posible colorear las ramas según los grupos y agregar un rectángulo alrededor de cada grupo.
Por ejemplo:
fviz_dend(hc, k = 4,
cex = 0.5,
k_colors = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
color_labels_by_k = TRUE,
rect = TRUE,
rect_border = "jco",
rect_fill = TRUE)Para cambiar el tema del gráfico, usa el argumento ggtheme, cuyos valores permitidos incluyen los temas oficiales de ggplot2 [theme_gray(), theme_bw(), theme_minimal(), theme_classic(), theme_void()] o cualquier otro tema de ggplot2 definido por el usuario.
fviz_dend(hc, k = 4,
cex = 0.5,
k_colors = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
color_labels_by_k = TRUE,
ggtheme = theme_gray()
)Los valores permitidos para k_color incluyen paletas Brewer del paquete RColorBrewer (por ejemplo, “RdBu”, “Blues”, “Dark2”, “Set2”, …) y paletas de revistas científicas del paquete ggsci de R (por ejemplo: “npg”, “aaas”, “lancet”, “jco”, “ucscgb”, “uchicago”, “simpsons” y “rickandmorty”).
En el código de R a continuación, cambiaremos los colores de los grupos usando la paleta de colores “jco” (Journal of Clinical Oncology):
Si quieres dibujar un dendrograma horizontal con un rectángulo alrededor de los clústeres, usa esto:
fviz_dend(hc, k = 4, cex = 0.4, horiz = TRUE, k_colors = "jco",
rect = TRUE, rect_border = "jco", rect_fill = TRUE)Además, puedes trazar un dendrograma circular usando la opción type = “circular”
Para trazar un árbol similar a un filogenético, use type = “phylogenic” y repel = TRUE (para evitar que las etiquetas se superpongan). Esta funcionalidad requiere el paquete de R igraph. Asegúrese de que esté instalado antes de escribir el siguiente código en R.
## Cargando paquete requerido: igraph
##
## Adjuntando el paquete: 'igraph'
## The following objects are masked from 'package:stats':
##
## decompose, spectrum
## The following object is masked from 'package:base':
##
## union
El diseño predeterminado para los árboles filogenéticos es “layout.auto”. Los valores permitidos son uno de: c(“layout.auto”, “layout_with_drl”, “layout_as_tree”, “layout.gem”, “layout.mds”, “layout_with_lgl”). Para leer más sobre estos diseños, consulte la documentación del paquete igraph de R.
Vamos a probar phylo.layout = “layout.gem”:
require("igraph")
fviz_dend(hc, k = 4, # Cut in four groups
k_colors = "jco",
type = "phylogenic", repel = TRUE,
phylo_layout = "layout.gem")Acercando el dendrograma
Si quieres acercar los primeros conglomerados, es posible usar la opción xlim y ylim para limitar el área del gráfico. Por ejemplo, escribe el siguiente código:
Trazando un subárbol de dendrogramas Para analizar en detalle secciones específicas del dendrograma, se puede visualizar un sub-árbol siguiendo un proceso de corte: primero, se genera y se guarda el dendrograma completo con fviz_dend(); luego, se utiliza la función base de R cut.dendrogram() para cortar el árbol a una altura específica, lo que resulta en una lista de sub-árboles; finalmente, se usa fviz_dend() para graficar el sub-árbol de interés, permitiendo enfocarse en la estructura de clustering de ramas particulares.
El código R es el siguiente.
• Corte el dendrograma y visualice la versión truncada:
# Create a plot of the whole dendrogram,
# and extract the dendrogram data
dend_plot <- fviz_dend(hc, k = 4, # Cut in four groups
cex = 0.5, # label size
k_colors = "jco"
)
dend_data <- attr(dend_plot, "dendrogram") # Extract dendrogram data
# Cut the dendrogram at height h = 10
dend_cuts <- cut(dend_data, h = 10)
# Visualize the truncated version containing
# two branches
fviz_dend(dend_cuts$upper)## Warning in min(-diff(our_dend_heights)): ningún argumento finito para min;
## retornando Inf
• Plot dendrograms sub-trees:
También puedes dibujar árboles circulares de la siguiente manera
Manipulación de dendrogramas usando dendextend
El paquete dendextend proporciona funciones para cambiar fácilmente la apariencia de un dendrograma y para comparar dendrogramas.
En esta sección utilizaremos el operador de encadenamiento (%>%) para simplificar nuestro código. El operador de encadenamiento convierte x %>% f(y) en f(x, y), de modo que puedes usarlo para reescribir múltiples operaciones de manera que se puedan leer de izquierda a derecha, de arriba hacia abajo. Por ejemplo, los resultados de los dos códigos R a continuación son equivalentes.
• Código R estándar para crear un dendrograma:
data <- scale(USArrests)
dist.res <- dist(data)
hc <- hclust(dist.res, method = "ward.D2")
dend <- as.dendrogram(hc)
plot(dend)• Código R para crear un dendrograma usando el operador de encadenamiento:
library(dendextend)
dend <- USArrests[1:5,] %>% # data
scale %>% # Scale the data
dist %>% # calculate a distance matrix,
hclust(method = "ward.D2") %>% # Hierarchical clustering
as.dendrogram # Turn the object into a dendrogram.
plot(dend)library(dendextend)
# 1. Create a customized dendrogram
mycols <- c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07")
dend <- as.dendrogram(hc) %>%
set("branches_lwd", 1) %>% # Branches line width
set("branches_k_color", mycols, k = 4) %>% # Color branches by groups
set("labels_colors", mycols, k = 4) %>% # Color labels by groups
set("labels_cex", 0.5) # Change label size
# 2. Create plot
fviz_dend(dend)Acerca de Dataset
Este conjunto de datos se adapta a partir del conjunto de datos de vino de https://archive.ics.uci.edu/ml/datasets/wine eliminando la información sobre los tipos de vino para el aprendizaje no supervisado.
Las siguientes descripciones se adaptan desde la página web de la UCI:
Estos datos son los resultados de un análisis químico de los vinos cultivados en la misma región en Italia pero derivados de tres cultivares diferentes. El análisis determinó las cantidades de 13 componentes encontradas en cada uno de los tres tipos de vinos. @wang2020wine
Los atributos son:
library(readr)
# 1. Cargar los datos desde el archivo CSV
wine_clustering <- read_csv("wine-clustering.csv")
# 2. Asignar los datos a 'df' y escalarlos
df <- wine_clustering
df <- scale(df) # Scaling the data
# 3. Ver las primeras 3 filas
head(df, n = 3)## Alcohol Malic_Acid Ash Ash_Alcanity Magnesium Total_Phenols
## [1,] 1.5143408 -0.56066822 0.2313998 -1.1663032 1.90852151 0.8067217
## [2,] 0.2455968 -0.49800856 -0.8256672 -2.4838405 0.01809398 0.5670481
## [3,] 0.1963252 0.02117152 1.1062139 -0.2679823 0.08810981 0.8067217
## Flavanoids Nonflavanoid_Phenols Proanthocyanins Color_Intensity Hue
## [1,] 1.0319081 -0.6577078 1.2214385 0.2510088 0.3611585
## [2,] 0.7315653 -0.8184106 -0.5431887 -0.2924962 0.4049085
## [3,] 1.2121137 -0.4970050 2.1299594 0.2682629 0.3174085
## OD280 Proline
## [1,] 1.8427215 1.0101594
## [2,] 1.1103172 0.9625263
## [3,] 0.7863692 1.3912237
Validacion del Cluster
## $H
## [1] 0.2844628
El valor obtenidos (0.2844628) es mucho menor que 0.5, lo que indica que estos datos sí tienen una fuerte tendencia a formar clusters naturales. Es decir, sí tiene sentido aplicar un análisis de clúster (como K-means o PAM) sobre el dataset presentado.
library(factoextra)
fviz_nbclust(df, kmeans, method = "wss") +
geom_vline(xintercept = 4, linetype = 2)Al aplicar el Método del Codo (Elbow Method) mediante la gráfica de la Suma Total de Cuadrados Dentro del Clúster (WSS) versus el número de clústeres (K), se observa un punto de inflexión o “codo” claramente definido en K=4.
Este punto indica que la disminución marginal en la varianza dentro de los clústeres se reduce significativamente a partir de la cuarta partición. Por lo tanto, se establece que el número óptimo y más eficiente de clústeres para el análisis K-means es K=4.
Cálculo del Clúster K-means en R
El algoritmo K-means inicia con centroides aleatorios, por lo que se usa set.seed() para garantizar la reproducibilidad de los resultados. Además, para asegurar la estabilidad del clúster, se especifica nstart = 25. Esto fuerza a R a probar 25 inicios diferentes y seleccionar la solución con la menor variación interna. El código implementa este método con la partición óptima de K=4 clústeres.
# Compute k-means with k = 4
set.seed(123)
km.res <- kmeans(df, 4, nstart = 25)
# Print the results
print(km.res)## K-means clustering with 4 clusters of sizes 28, 56, 49, 45
##
## Cluster means:
## Alcohol Malic_Acid Ash Ash_Alcanity Magnesium Total_Phenols
## 1 -0.7869073 0.04195151 0.2157781 0.3683284 0.43818899 0.6543578
## 2 0.9580555 -0.37748461 0.1969019 -0.8214121 0.39943022 0.9000233
## 3 0.1860184 0.90242582 0.2485092 0.5820616 -0.05049296 -0.9857762
## 4 -0.9051690 -0.53898599 -0.6498944 0.1592193 -0.71473842 -0.4537841
## Flavanoids Nonflavanoid_Phenols Proanthocyanins Color_Intensity Hue
## 1 0.5746004 -0.5429201 0.8888549 -0.7346332 0.2830335
## 2 0.9848901 -0.6204018 0.5575193 0.2423047 0.4799084
## 3 -1.2327174 0.7148253 -0.7474990 0.9857177 -1.1879477
## 4 -0.2408779 0.3315072 -0.4329238 -0.9177666 0.5202140
## OD280 Proline
## 1 0.60628629 -0.5169332
## 2 0.76926636 1.2184972
## 3 -1.29787850 -0.3789756
## 4 0.07869143 -0.7820425
##
## Clustering vector:
## [1] 2 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2
## [38] 2 2 2 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 4 4 4 4 1 4 1 2 4 4 1 4 1 4 1
## [75] 1 4 4 4 1 1 4 4 4 3 1 4 4 4 4 4 4 4 4 1 1 1 1 4 1 1 4 4 1 4 4 4 4 4 4 1 1
## [112] 4 4 4 4 4 4 4 4 4 1 1 1 1 1 4 1 4 4 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
## [149] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
##
## Within cluster sum of squares by cluster:
## [1] 307.0966 268.5747 302.9915 289.9515
## (between_SS / total_SS = 49.2 %)
##
## Available components:
##
## [1] "cluster" "centers" "totss" "withinss" "tot.withinss"
## [6] "betweenss" "size" "iter" "ifault"
Interpretación de la Salida de K-means
El resultado impreso del algoritmo K-means proporciona dos elementos de salida fundamentales para el análisis: primero, la matriz de Medias o Centros del Clúster, la cual detalla el valor promedio de cada variable dentro de cada uno de los clústeres formados, sirviendo para caracterizar y nombrar los grupos; y segundo, el Vector de Clustering, que es una asignación de enteros indicando con precisión a qué clúster final ha sido asociado cada punto u observación individual del conjunto de datos.
Es posible calcular la media de cada variable por clústeres usando los datos originales:
## cluster Alcohol Malic_Acid Ash Ash_Alcanity Magnesium Total_Phenols
## 1 1 12.36179 2.383214 2.425714 20.72500 106.00000 2.704643
## 2 2 13.77839 1.914643 2.420536 16.75179 105.44643 2.858393
## 3 3 13.15163 3.344490 2.434694 21.43878 99.02041 1.678163
## 4 4 12.26578 1.734222 2.188222 20.02667 89.53333 2.011111
## Flavanoids Nonflavanoid_Phenols Proanthocyanins Color_Intensity Hue
## 1 2.6032143 0.2942857 2.099643 3.355000 1.0221429
## 2 3.0130357 0.2846429 1.910000 5.619821 1.0671429
## 3 0.7979592 0.4508163 1.163061 7.343265 0.6859184
## 4 1.7886667 0.4031111 1.343111 2.930444 1.0763556
## OD280 Proline
## 1 3.042143 584.1071
## 2 3.157857 1130.6071
## 3 1.690204 627.5510
## 4 2.667556 500.6222
Interpretación de las medias por clúster
La tabla muestra el perfil promedio de cada uno de los 4 clústeres identificados por k-means usando las variables químicas del vino. Comparando las medias de cada clúster, puedes entender qué caracteriza a cada grupo y por qué fueron separados por el algoritmo.
Clúster 1 – Vinos de intensidad moderada y composición equilibrada
Vinos más suaves, equilibrados, menos intensos y de menor concentración fenólica.
Características principales:
Alcohol moderado (≈12.36)
Acidez málica relativamente alta
Fenoles totales y flavonoides medios
Intensidad de color baja-moderada (≈3.35)
Proline bajo (≈584)
Clúster 2 – Vinos de mayor graduación y más intensidad
Vinos más complejos, estructurados, concentrados y de mayor intensidad aromática y color.
Características:
Mayor grado alcohólico (≈13.78), el más alto de todos
Fenoles y flavonoides altos
Intensidad de color elevada (≈5.62)
Proline muy alto (≈1130)
Clúster 3 – Vinos muy intensos en color, pero con bajos flavonoides
vinos con mucho color pero menor complejidad polifenólica; perfil atípico respecto a los demás.
Características:
Alcohol medio (≈13.15)
Malic Acid alto
Flavonoids muy bajos (≈0.79) → poco aporte de amargor y estructura
Color_Intensity altísimo (≈7.34)
Proline moderado (≈672)
Clúster 4 – Vinos más ligeros
Vinos más ligeros, menos intensos, menos estructurados y posiblemente más simples.
Características:
Alcohol bajo (≈12.27)
Fenoles y flavonoides bajos
Intensidad de color muy baja (≈2.93)
Proline muy bajo (≈500)
Si quieres agregar las clasificaciones de puntos a los datos originales, usa esto:
## Alcohol Malic_Acid Ash Ash_Alcanity Magnesium Total_Phenols Flavanoids
## 1 14.23 1.71 2.43 15.6 127 2.80 3.06
## 2 13.20 1.78 2.14 11.2 100 2.65 2.76
## 3 13.16 2.36 2.67 18.6 101 2.80 3.24
## 4 14.37 1.95 2.50 16.8 113 3.85 3.49
## 5 13.24 2.59 2.87 21.0 118 2.80 2.69
## 6 14.20 1.76 2.45 15.2 112 3.27 3.39
## Nonflavanoid_Phenols Proanthocyanins Color_Intensity Hue OD280 Proline
## 1 0.28 2.29 5.64 1.04 3.92 1065
## 2 0.26 1.28 4.38 1.05 3.40 1050
## 3 0.30 2.81 5.68 1.03 3.17 1185
## 4 0.24 2.18 7.80 0.86 3.45 1480
## 5 0.39 1.82 4.32 1.04 2.93 735
## 6 0.34 1.97 6.75 1.05 2.85 1450
## cluster
## 1 2
## 2 2
## 3 2
## 4 2
## 5 1
## 6 2
Accediendo a los resultados de la función kmeans()
Accediento al número de clúster para cada una de las observaciones
## [1] 2 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2
## [38] 2 2 2 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 4 4 4 4 1 4 1 2 4 4 1 4 1 4 1
## [75] 1 4 4 4 1 1 4 4 4 3 1 4 4 4 4 4 4 4 4 1 1 1 1 4 1 1 4 4 1 4 4 4 4 4 4 1 1
## [112] 4 4 4 4 4 4 4 4 4 1 1 1 1 1 4 1 4 4 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
## [149] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
## [1] 2 2 2 2
Accediendo al tamaño de cada clúster
## [1] 28 56 49 45
Clúster Tamaño (Número de Observaciones)
Clúster 1 –> 28 observaciones Clúster 2 –> 56 observaciones Clúster 3 –> 49 observaciones Clúster 4 –> 45 observaciones Total (Muestra Total) –> 178 (28 + 56 + 49 + 45)
Accediendo a la matriz de centros de clúster (medias de clúster)
## Alcohol Malic_Acid Ash Ash_Alcanity Magnesium Total_Phenols
## 1 -0.7869073 0.04195151 0.2157781 0.3683284 0.43818899 0.6543578
## 2 0.9580555 -0.37748461 0.1969019 -0.8214121 0.39943022 0.9000233
## 3 0.1860184 0.90242582 0.2485092 0.5820616 -0.05049296 -0.9857762
## 4 -0.9051690 -0.53898599 -0.6498944 0.1592193 -0.71473842 -0.4537841
## Flavanoids Nonflavanoid_Phenols Proanthocyanins Color_Intensity Hue
## 1 0.5746004 -0.5429201 0.8888549 -0.7346332 0.2830335
## 2 0.9848901 -0.6204018 0.5575193 0.2423047 0.4799084
## 3 -1.2327174 0.7148253 -0.7474990 0.9857177 -1.1879477
## 4 -0.2408779 0.3315072 -0.4329238 -0.9177666 0.5202140
## OD280 Proline
## 1 0.60628629 -0.5169332
## 2 0.76926636 1.2184972
## 3 -1.29787850 -0.3789756
## 4 0.07869143 -0.7820425
Visualizando los clústeres de k-means
Para visualizar la separación de clústeres cuando hay muchas variables, se aplica PCA (Análisis de Componentes Principales). Esta técnica reduce la dimensionalidad a dos componentes, permitiendo un gráfico de dispersión 2D donde los puntos se colorean según su clúster. La función fviz_cluster() facilita esta interpretación visual sobre el plano PCA.
fviz_cluster(km.res, data = df,
palette = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
ellipse.type = "euclid", # Concentration ellipse
star.plot = TRUE, # Add segments from centroids to items
repel = TRUE, # Avoid label overplotting (slow)
ggtheme = theme_minimal()
)Kassambara, A. 2017. Practical Guide to Cluster Analysis in r: Unsupervised Machine Learning. Multivariate Analysis. STHDA. https://books.google.com.sv/books?id=-q3snAACAAJ.
Wang, Harry. 2020. “Wine Dataset for Clustering.” https://www.kaggle.com/datasets/harrywang/wine-dataset-for-clustering; Kaggle.