MÉTODOS PARA EL ANÁLISIS ECONÓMICO
TEMA DE INVESTIGACIÓN: ANÁLISIS DE CLÚSTER (CONGLOMERADOS)
El análisis de conglomerados es una técnica de aprendizaje no supervisado cuyo objetivo es agrupar un conjunto de objetos u observaciones en grupos o “conglomerados”, de manera que los elementos dentro de un mismo grupo sean más similares entre sí que con los objetos pertenecientes a otros grupos. Esta lógica de agrupamiento—basada en la similitud interna y la heterogeneidad externa—constituye el principio fundamental del clustering A. Kassambara (, 2017) .
Según Kassambara (2017), el análisis de conglomerados implica tres etapas principales:
Medir la similitud o disimilitud entre las observaciones mediante una métrica de distancia adecuada.
Aplicar un algoritmo de agrupamiento, ya sea jerárquico o no jerárquico, para estructurar los datos en grupos.
Interpretar los conglomerados, identificando patrones comunes dentro de cada grupo y diferencias relevantes entre ellos.
El análisis de conglomerados busca revelar estructuras ocultas o patrones naturales presentes en los datos sin utilizar información previa ni etiquetas de clasificación. En este sentido, su propósito central es descubrir, resumir y comprender la heterogeneidad de los datos mediante la formación de conglomerados que sean internamente homogéneos y externamente heterogéneos A. Kassambara (, 2017) .
Resumen análisis de clúster
|
Análisis de Clúster |
Definición |
Técnicas disponibles |
Ventajas |
Desventajas |
|
Jerárquico |
Es un método que construye una estructura incremental de agrupamiento mediante la aplicación repetida de medidas de proximidad entre observaciones.
El proceso genera un dendograma, que representa relaciones jerárquicas entre los objetos y permite identificar clústers a diferentes niveles. |
Métodos de enlace (linkage methods): - Single linkage (puente más corto)
- Complete linkage (puente más largo)
- Average linkage (UPGMA)
- Centroid linkage
- Ward´s method (minimiza varianza)
Métodos aglomerativos vs. divisivos |
- No requiere definir el número de clústers (K). Se elige visualmente según el dendograma y la distancia de corte. - El dendograma permite interpretar la estructura subyacente de los datos, revelando patrones, subgrupos y niveles de similitud. - Flexibilidad para diferentes formas de clúster, dependiendo del método de enlace. - Habilidad para trabajar con datos mixtos usando distancias apropiadas (ej. Gower) - Útil para análisis exploratorio, especialmente cuando no existe hipótesis clara sobre el número de grupos. |
- Costo computacional alto, ya que requiere calcular una matriz de distancias completas (n x n). Kassambara enfatiza que no es recomendable para “n” muy grandes. - Los resultados dependen fuertemente del método de enlace y de la métrica de distancia. (distintas combinaciones = estructuras radicalmente diferentes). - El proceso es irreversible: una vez que dos clústeres se unen, no pueden separarse. - Puede ser inestable frente a outliers. - Sensibilidad elevada al reescalamiento de variables. |
|
No Jerárquico |
El clúster no jerárquico (o particional) es un conjunto de métodos que asignan directamente cada observación a uno de K clústeres definidos previamente. |
- K-Means: El algoritmo más conocido; usa medias (centroides). Requiere datos numéricos continuos. - K-Medoids (PAM – Partitioning Around Medoids): Más robusto que K-means, usa observaciones reales como centros. Ideal con outliers. - CLARA: Versión eficiente de PAM para bases grandes; trabaja con muestreos. - K-Modes / K-Prototypes: para datos categóricos o mixtos. - Fuzzy C-Means: Permite pertenencia simultánea a varios clústeres. |
-
Altamente eficientes con grandes bases de datos. - Resultados más compactos y claros, especialmente con K-means o Ward. - Algoritmos iterativos que pueden reclasificar observaciones, mejorando la calidad final del agrupamiento. - Fáciles de interpretar, especialmente mediante centroides o medoids. - Disponibilidad de variaciones robustas (PAM, CLARA, K-prototypes). - Flexibles para grandes volúmenes de datos, donde los jerárquicos fallan.
|
-
Requiere especificar K antes de iniciar. - Puede converger en soluciones locales, no óptimas, especialmente K-means. - Sensibles a outliers, sobre todo K-means. - Supone clústeres convexos y de tamaño similar, lo que no siempre es realista.
-
Dependencia del reescalamiento.
|
Fuente:Elaboración propia con base en Kassambara (2017)
El análisis de clúster permite agrupar observaciones según su similitud. Kassambara (2017) distingue dos grandes familias de técnicas:
Métodos jerárquicos
Métodos no jerárquicos (o particionales)
A continuación se describen ambos tipos, sus variantes principales y cómo se implementan en R, incluyendo librerías recomendadas por Kassambara: stats, cluster, factoextra, dendextend.
Fusiona clústeres según la menor distancia entre pares de puntos.
Fusiona según la mayor distancia entre puntos de los clústeres.
Utiliza el promedio de distancias entre todos los puntos de dos clústeres.
Fusiona clústeres según la distancia entre sus centroides.
Minimiza la varianza dentro de cada clúster.
Cálculo de matriz de distancias dist_matrix <- dist(df, method = “euclidean”)
Clustering jerárquico hc <- hclust(dist_matrix, method = “ward.D2”)
Dendrograma plot(hc, hang = -1)
Corte del dendrograma para obtener k clústeres clusters <- cutree(hc, k = 4)
Visualización con factoextra library(factoextra) fviz_dend(hc, k = 4, rect = TRUE)
Personalización avanzada con dendextend library(dendextend) dend <- as.dendrogram(hc) dend %>% color_branches(k = 4) %>% plot()
K-means (librería: stats) set.seed(123) km <- kmeans(df, centers = 3, nstart = 25) km$cluster
Visualización fviz_cluster(km, data = df)
PAM library(cluster) pam_res <- pam(df, k = 3) fviz_cluster(pam_res, data = df)
CLARA clara_res <- clara(df, k = 3) fviz_cluster(clara_res, data = df)
Carga de datos utilizando, data “USArrests”
## 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
library(factoextra)
fviz_nbclust(df, kmeans, method = "wss") +
geom_vline(xintercept = 4, linetype = 2)El grafico anterior representa la varianza dentro de los grupos. Disminuye a medida que k aumenta, pero se puede ver una curva (o “codo”) en k = 4.Esta curva indica que los grupos adicionales mas alla del cuarto tienen poco valor. En la siguiente seccion, clasificaremos las observaciones en 4 racimos.
El codigo R a continuacion realiza la agrupacion K-medias con K=4
# Calcule k-means con k = 4
set.seed(123)
km.res <- kmeans(df, 4, nstart = 25)
# Imprime los resultado
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"
La salida impresa muestra:
Las medias o centros de los clusteres : una matriz cuya fila son el numero de cluster(1 a 4) y las columnas son las variables.
El vector de agrupamiento: un vector de enteros(de 1 a k) que indica el cluster al que se asigna cada punto.
## 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 desea agregar las clasificaciones de puntos a los datos originales, use 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
## 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
## Alabama Alaska Arizona Arkansas
## 1 4 4 1
## [1] 8 13 16 13
## 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
data("USArrests") # Cargar el conjunto de datos
df <- scale(USArrests) # Escalar los datos
head(df, n = 3) # Ver las primeras 3 filas de los datos## 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
A partir del grafico el numero sugerido de clusters es 2.
El siguiente código R 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 medoides del clúster: una matriz, cuyas filas son los medoides y las columnas son variables • El vector de agrupamiento: un vector de números enteros (de 1: k) que indica el grupo al que se asigna cada punto.
Si desea agregar las clasificaciones de puntos a los datos originales, use 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
La funcion pam() devuelve un objeto de clase pam cuyos componentes incluyen: • Medoides : objetos que representan grupos(clusteres) • Clustering : un vector que contiene el numero de agrupacion de cada objeto
Se puede acceder a estos componentes de la siguiente manera:
## Murder Assault UrbanPop Rape
## New Mexico 0.8292944 1.3708088 0.3081225 1.1603196
## Nebraska -0.8008247 -0.8250772 -0.2445636 -0.5052109
## Alabama Alaska Arizona Arkansas California Colorado
## 1 1 1 2 1 1
Para calcular el algoritmo CLARA en R,los datos deben prepararse como se indica en el capitulo 2. Aqui generaremos un conjunto de datos aleatorios. Para que el resultado sea reproducible, comenzamos utilizando la función set.seed ().
set.seed(1234)
#Generar 500 objetos, divididos en 2 grupos
df <- rbind(cbind(rnorm(200, 0, 8), rnorm(200, 0, 8)),
cbind(rnorm(300, 50, 8), rnorm(300, 50, 8)))
#Especificar nombres de filas y columnas
colnames(df) <- c("x", "y")
rownames(df) <- paste0("S", 1:nrow(df))
#Vista previa de los datos
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
Para estimar el numero optimo de clusteres en sus datos, es posible utilizar el metodo de silueta promedio,como se describe en el capitulo de agrupamiento de PAM (Capítulo 5). La function fviz_nbclust () [ paquete factoextra ] proporciona una solucion 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 grupos es 2.
El codigo R que se muestra a continuacion, calcula el algoritmo PAM con k = 2:
#Calculo de CLARA
clara.res <- clara(df, 2, samples = 50, pamLike = TRUE)
#Imprime los componentes de 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:
medoides: Objetos que representan clusteres(grupos)
agrupamiento: Un vector que contiene el numero de grupo de cada objeto
muestra: Etiquetas o numeros de caso de las observaciones en la mejor muestra, es decir, la muestra utilizada por el algoritmo clara para la particion final.
Si desea agregar las clasificaciones de puntos a los datos originales, utilize lo siguiente:
## 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
Puede 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
Los medoides son S121, S455
Para visualizar los resultados de la particion, usaremos la funcion fviz_cluster () [el paquete factoextra].
fviz_cluster(
clara.res,
palette = c("#00AFBB", "#FC4E07"),
# color palette
ellipse.type = "t",
# Concentration ellipse
geom = "point",
pointsize = 1,
ggtheme = theme_classic()
)# Cargar los datos
data("USArrests")
# Estandarizar los datos
df <- scale(USArrests)
# Mostrar las primeras 6 filas
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
# Calcule la matriz de disimilitud
# df = los datos estandarizados
res.dist <- dist(df, method = "euclidean")
as.matrix(res.dist)[1:6, 1:6]## 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
# Calcule la distancia cophentic
res.coph <- cophenetic(res.hc)
# Correlacion entre distancia cofenetica y
# la distancia original
cor(res.dist, res.coph)## [1] 0.6975266
Ejecute la funcion hclust () nuevamente usando el metodo de vinculacion promedio. A continuacion, llame cophenetic () para evaluar la solucion de agrupamiento.
## [1] 0.7180382
## 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 facilmente utilizando la funcion fviz_dend() [en factoextra]
#Dividir en 4 grupos y colorear por grupos
fviz_dend(
res.hc,k = 4,#Cortar en 4 grupos
cex = 0.5,#Tamaño de la etiqueta
k_colors = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
color_labels_by_k = TRUE,#Colorer etiquetas por grupos
rect = TRUE #Agregar rectangulo alrededor de los grupos
)Usando la funcion fviz_cluster () [in factoextra], tambien podemos visualizar el resultado en un diagrama de dispersion. Las observaciones estan representadas por puntos en la grafica, usando el metodo de 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",
# Elipse de concentración
repel = TRUE,
# # Evite el trazado excesivo de etiquetas (lento)
show.clust.cent = FALSE,
ggtheme = theme_minimal()
)Las funciones se pueden ejecutar de la siguiente manera:
library("cluster")
#Anidacion aglomerativa (agrupacion jerarquica)
res.agnes <- agnes(x = USArrests,#matriz de datos
stand = TRUE,#Estandarizar los datos
metric = "euclidean",#metrica para matriz de distancia
method = "ward" # Metodo de vinculacion
)
# Agrupacion de analisis visual
res.diana <- diana(x = USArrests, # matriz de datos
stand = TRUE, # estandarizar los datos
metric = "euclidean" # metrica para matriz de distancia
)Despues de ejecutar agnes () y diana (), puede usar la funcion fviz_dend () [in factoextra] para visualizar la salida:
library(dendextend)
# Calcular la matriz de distancias
res.dist <- dist(df, method = "euclidean")
# Calcule 2 agrupaciones jerárquicas
hc1 <- hclust(res.dist, method = "average")
hc2 <- hclust(res.dist, method = "ward.D2")
# Crear dos dendogramas
dend1 <- as.dendrogram (hc1)
dend2 <- as.dendrogram (hc2)
# Crea una lista para contener dendrogramas
dend_list <- dendlist(dend1, dend2)Dibuja un tanglegrama:
Personalizar el tanglegrama usando muchas otras opciones como se muestra a continuacion:
tanglegram(dend1, dend2,
highlight_distinct_edges = FALSE, #Desactivar lineas discontinuas
common_subtrees_color_lines = FALSE, #Desactivar colores de linea
common_subtrees_color_branches = TRUE, #Colorear ramas comunes
main = paste("entanglement =", round(entanglement(dend_list), 2))
)## [,1] [,2]
## [1,] 1.0000000 0.9925544
## [2,] 0.9925544 1.0000000
## [,1] [,2]
## [1,] 1.0000000 0.9895528
## [2,] 0.9895528 1.0000000
La correlacion entre dos arboles tambien se puede calcular de la siguiente manera:
## [1] 0.9925544
## [1] 0.9895528
Tambien es posible comparar simultaneamente varios dendrogramas. Se utiliza un operador de encadenamiento %>% para ejecutar varias funciones al mismo tiempo. Es util para simplificar el codigo:
#Crea múltiples dendrogramas encadenando
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
#Calcular matriz de correlacion
dend_list <- dendlist("Complete" = dend1,"Single" = dend2,
"Average" = dend3,"Centroid" = dend4)
cors <- cor.dendlist(dend_list)
#Imprimir matriz de correlacion
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
# Visualice la matriz de correlacion usando el paquete corrplot
library(corrplot)
corrplot(cors, "pie", "lower")Comenzamos calculando el agrupacion jerarquico utilizando los conjuntos de datos de USArrests:
#Cargar datos
data(USArrests)
#Calcular distancias y agrupamiento jerarquico
dd <- dist(scale(USArrests), method = "euclidean")
hc <- hclust(dd, method = "ward.D2")Para crear un dendrograma basico, escriba lo siguiente:
Puede usar los argumentos main, sub, xlab, ylab para cambiar los titulos de los graficos de la siguiente manera:
fviz_dend(hc, cex = 0.5,
main = "Dendrogram - ward.D2",
xlab = "Objects", ylab = "Distance", sub = "")Para dibujar un dendrograma horizontal, escriba lo siguiente:
Tambien es posible cortar el arbol a una altura determinada para particionar los datos en multiples grupos, como se describe en el capitulo anterior: Agrupamiento jerarquico (Capitulo 7). En este caso, es posible colorear las ramas por grupos y añadir un rectangulo alrededor de cada grupo. Por Ejemplo:
fviz_dend(hc, k = 4, #Dividir en cuatro grupos
cex = 0.5, # Tamaño de etiqueta
k_colors = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
color_labels_by_k = TRUE, #Colorear etiquetas por grupos
rect = TRUE, #Agregar un rectangulo alrededor del grupo
rect_border = "jco",
rect_fill = TRUE)Para cambiar el tema del grafico, use 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, #Dividir en cuatro grupos
cex = 0.5, #tamaño de etiqueta
k_colors = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
color_labels_by_k = TRUE, #Colorear etiquetas por grupos
ggtheme = theme_gray() #Cambiar tema
)Si desea dibujar un dendrograma horizontal con un rectangulo alrededor de los grupos, use esto:
fviz_dend(hc,k = 4,cex = 0.4,horiz = TRUE,k_colors = "jco",
rect = TRUE,rect_border = "jco",rect_fill = TRUE)Ademas, puede trazar un dendrograma circular usando la opcion type = “circular.”
Para graficar un arbol filogenetico, use type = “phylogenic” y repel = TRUE (para evitar que las etiquetas se superpongan). Esta funcionalidad requiere el paquete igraph de R. Asegúrese de que este instalado antes de escribir el siguiente código de R.
## Cargando paquete requerido: igraph
## Warning: package 'igraph' was built under R version 4.4.3
##
## Adjuntando el paquete: 'igraph'
## The following objects are masked from 'package:stats':
##
## decompose, spectrum
## The following object is masked from 'package:base':
##
## union
La estructura predeterminada para los arboles filogeneticos es «layout.auto». Los valores permitidos son: c(“layout.auto”, “layout_with_drl”, “layout_as_tree”, “layout.gem”, “layout.mds”,“layout_with_lgl”). Para obtener más informacion sobre estas estructuras, consulte la documentacion del paquete igraph de R.
Probemos con phylo.layout = “layout.gem”:
require("igraph")
fviz_dend(hc, k = 4, #Dividir en cuatro grupos
k_colors = "jco",
type = "phylogenic", repel = TRUE,
phylo_layout = "layout.gem")Corte el dendrograma y visualice la version truncada
#Cree una grafica del dendograma completo,
#y extraiga los datos del dendrograma
dend_plot <- fviz_dend(hc,k = 4,
cex = 0.5,
k_colors = "jco")
dend_data <-attr(dend_plot, "dendrogram") #Extraer datos del dendrograma
#Cortar el dendrograma a la altura h= 10
dend_cuts <- cut(dend_data, h = 10)
#Visualizar la version truncada que contiene
#dos ramas
fviz_dend(dend_cuts$upper)Tambien puede trazar arboles circulares de la siguiente manera:
pdf("dendrogram.pdf", width=30, height=15)
p <- fviz_dend(hc, k = 4, cex = 1, k_colors = "jco" )
print(p)
dev.off()## png
## 2
Codigo R estandar para crear un dendrograma:
data <- scale(USArrests)
dist.res <- dist(data)
hc <- hclust(dist.res, method = "ward.D2")
dend <- as.dendrogram(hc)
plot(dend)Codigo R para crear un dendrograma usando un operador de encadenamiento:
library(dendextend)
dend <- USArrests[1:5, ] %>% #datos
scale %>% #Escala de datos
dist %>% #calcular una matriz de distancia,
hclust(method = "ward.D2") %>% #Agrupamiento jerarquico
as.dendrogram #Convierte el objeto en un dendrograma.
plot(dend)Funciones para personalizar dendrogramas: La funcion set() [del paquete dendextend] permite modificar los parametros de un dendrograma. El formato es:
set(object, what, value)
Ejemplos:
library(dendextend)
# 1.Crea un dendrograma personalizado
mycols <- c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07")
dend <- as.dendrogram(hc) %>%
set("branches_lwd", 1) %>% # Ancho de linea de ramas
set("branches_k_color", mycols, k = 4) %>% # Colorea ramas por grupos
set("labels_colors", mycols, k = 4) %>% # Etiquetas de color por grupos
set("labels_cex", 0.5) # Cambiar el tamaño de la etiqueta
# 2. Crea una trama
fviz_dend(dend)El objetivo de este caso es ofrecer una vision integrada de los pasos que requiere la aplicacion de un análisis de conglomerados. En este ejercicio aplicaremos el procedimiento al dataset Customer Personality Analysis (Kaggle), con el objetivo de identificar segmentos de clientes con perfiles de consumo y comportamiento similares para diseñar estrategias comerciales diferenciadas.
library(readr)
library(dplyr)
library(tidyverse)
library(MASS)
library(knitr)
library(kableExtra)
library(factoextra)
Customer_Personality <- read_delim("C:/Users/HP/Downloads/Customer_Personality.csv",
delim = "\t", escape_double = FALSE,
trim_ws = TRUE)
head(Customer_Personality)## # A tibble: 6 × 29
## ID Year_Birth Education Marital_Status Income Kidhome Teenhome Dt_Customer
## <dbl> <dbl> <chr> <chr> <dbl> <dbl> <dbl> <chr>
## 1 5524 1957 Graduation Single 58138 0 0 04-09-2012
## 2 2174 1954 Graduation Single 46344 1 1 08-03-2014
## 3 4141 1965 Graduation Together 71613 0 0 21-08-2013
## 4 6182 1984 Graduation Together 26646 1 0 10-02-2014
## 5 5324 1981 PhD Married 58293 1 0 19-01-2014
## 6 7446 1967 Master Together 62513 0 1 09-09-2013
## # ℹ 21 more variables: Recency <dbl>, MntWines <dbl>, MntFruits <dbl>,
## # MntMeatProducts <dbl>, MntFishProducts <dbl>, MntSweetProducts <dbl>,
## # MntGoldProds <dbl>, NumDealsPurchases <dbl>, NumWebPurchases <dbl>,
## # NumCatalogPurchases <dbl>, NumStorePurchases <dbl>,
## # NumWebVisitsMonth <dbl>, AcceptedCmp3 <dbl>, AcceptedCmp4 <dbl>,
## # AcceptedCmp5 <dbl>, AcceptedCmp1 <dbl>, AcceptedCmp2 <dbl>, Complain <dbl>,
## # Z_CostContact <dbl>, Z_Revenue <dbl>, Response <dbl>
vars <- c("Income", "MntWines", "MntFruits", "MntMeatProducts",
"MntFishProducts", "MntSweetProducts", "MntGoldProds")
# Creación dataframe limpio (sin NA)
df_clean <- Customer_Personality %>%
dplyr::select(all_of(vars)) %>%
drop_na()
# Estandarizando
df_scaled <- scale(df_clean)
p <- ncol(df_scaled) # grados de libertad (número de variables)
head(df_scaled, n = 3)## Income MntWines MntFruits MntMeatProducts MntFishProducts
## [1,] 0.2340099 0.9780050 1.5490798 1.6898454 2.454014
## [2,] -0.2345065 -0.8718271 -0.6371840 -0.7178241 -0.650891
## [3,] 0.7693040 0.3584298 0.5690305 -0.1783278 1.339901
## MntSweetProducts MntGoldProds
## [1,] 1.4844919 0.84983876
## [2,] -0.6337371 -0.73270190
## [3,] -0.1467879 -0.03792796
fviz_nbclust(df_scaled, kmeans, method = "wss") +
geom_vline(xintercept = 5, linetype = 2) +
labs(subtitle = "Método del codo")# Compute k-means with k = 5
set.seed(123)
km.res <- kmeans(df_scaled, 5, nstart = 25)
print(km.res)## K-means clustering with 5 clusters of sizes 450, 283, 256, 1064, 163
##
## Cluster means:
## Income MntWines MntFruits MntMeatProducts MntFishProducts
## 1 0.3495149 0.4215007 -0.1744109 -0.1527252 -0.15232037
## 2 0.8564471 0.5846308 1.8117405 1.0653512 1.73493565
## 3 1.1317282 1.3742487 0.4755803 1.6359933 0.64607741
## 4 -0.6979310 -0.7571264 -0.5423108 -0.6336588 -0.56092631
## 5 0.3265028 0.6052087 0.1290336 0.1388380 0.05513592
## MntSweetProducts MntGoldProds
## 1 -0.147437203 -0.09535402
## 2 1.826818913 0.91407875
## 3 0.493188860 0.06173471
## 4 -0.541907859 -0.56201939
## 5 -0.001898143 2.24791149
##
## Clustering vector:
## [1] 2 4 1 4 1 1 1 4 4 4 4 2 4 4 3 4 4 5 4 4 3 1 1 1 4 4 4 3 4 4 4 4 3 4 1 4 4
## [38] 1 2 4 4 4 2 4 4 3 1 3 4 2 5 2 2 4 1 3 1 5 1 2 4 4 3 5 3 3 2 1 4 4 3 2 4 1
## [75] 4 4 4 4 1 4 4 4 2 4 4 4 4 1 4 5 1 4 4 2 3 3 4 4 2 4 2 3 3 1 1 1 4 2 2 4 4
## [112] 1 4 4 4 5 5 2 4 1 1 1 5 4 3 4 4 4 4 3 1 3 1 5 1 4 4 4 4 1 1 1 4 1 1 4 4 4
## [149] 3 4 3 4 1 3 4 1 4 2 4 4 4 4 4 4 3 2 4 4 5 4 4 5 4 4 4 4 5 3 4 4 2 4 4 4 4
## [186] 1 3 2 4 1 2 3 2 4 4 4 4 4 5 4 3 4 1 2 1 4 3 4 1 4 3 1 4 1 4 5 1 3 4 4 2 4
## [223] 4 1 4 4 1 4 4 2 2 4 2 5 4 3 3 2 2 4 4 2 4 3 4 1 4 4 4 4 1 4 4 4 4 2 4 2 4
## [260] 3 4 4 4 4 1 2 2 3 5 4 5 4 1 4 4 2 5 2 4 4 4 2 4 4 1 4 4 1 1 4 1 4 4 4 2 4
## [297] 3 1 4 4 4 3 4 4 4 1 4 1 4 4 3 1 5 4 4 4 4 4 4 1 4 4 5 2 4 3 2 3 4 1 1 4 2
## [334] 4 2 4 4 1 2 3 3 1 4 4 2 1 1 2 1 4 4 1 5 3 4 2 1 4 4 4 5 4 4 4 4 5 4 4 4 4
## [371] 4 4 4 1 5 4 1 2 4 2 4 1 3 4 4 4 4 4 2 4 5 1 4 4 1 4 1 4 2 1 1 5 3 4 3 2 1
## [408] 4 4 4 3 3 4 2 1 4 2 3 5 2 5 4 4 1 1 4 4 4 4 4 4 4 4 4 2 4 1 1 1 4 1 1 4 2
## [445] 4 4 2 1 2 4 2 4 3 3 4 1 1 2 4 1 4 4 5 4 1 1 5 4 4 4 4 1 2 1 1 4 4 3 4 3 5
## [482] 1 1 4 3 1 1 4 4 4 5 4 5 2 2 4 2 4 2 4 2 4 3 4 4 1 3 4 5 4 3 4 4 3 1 2 1 1
## [519] 3 1 1 4 4 4 2 1 4 4 4 1 3 1 4 3 4 4 4 4 4 1 4 2 4 5 2 4 3 4 2 1 2 4 4 1 4
## [556] 4 4 1 4 4 1 4 1 4 4 4 4 4 1 4 4 4 4 5 1 1 4 4 2 2 4 1 4 4 4 4 4 4 1 3 1 4
## [593] 4 4 4 4 3 4 4 4 4 1 4 4 1 4 4 1 4 1 4 5 4 2 3 4 4 3 1 2 4 2 4 5 1 3 3 5 3
## [630] 1 5 3 4 2 4 1 5 3 4 3 4 4 1 4 4 2 4 1 4 2 4 4 4 4 4 4 4 3 1 2 2 1 4 1 1 4
## [667] 1 5 2 1 4 3 1 2 3 3 3 1 5 4 4 4 4 4 4 1 3 1 1 5 3 4 2 4 1 5 4 4 1 4 1 4 2
## [704] 2 4 5 4 1 5 4 2 4 4 3 2 1 5 4 1 5 4 3 3 2 1 4 2 1 4 4 4 3 5 4 2 4 1 3 1 2
## [741] 3 2 2 1 5 4 4 4 1 2 4 5 4 3 2 4 1 1 5 5 4 4 4 4 3 4 2 2 4 4 4 4 4 4 5 5 4
## [778] 2 1 4 4 4 4 1 5 2 4 1 4 4 2 3 1 4 1 5 2 4 4 2 1 2 1 4 1 1 4 3 4 1 4 3 2 3
## [815] 4 3 4 4 5 1 4 4 2 1 5 4 5 4 4 4 4 3 3 5 1 4 4 1 1 2 4 4 2 4 1 4 1 4 4 4 1
## [852] 1 1 4 4 5 4 3 1 4 4 5 2 1 4 3 4 4 4 4 4 2 2 4 4 1 3 4 1 5 4 1 5 5 2 4 4 3
## [889] 4 3 1 4 5 3 4 4 4 3 3 5 4 3 2 1 3 1 3 4 5 4 4 2 5 2 2 2 3 3 4 1 4 5 4 2 3
## [926] 5 1 2 5 2 3 4 1 5 1 4 1 4 4 4 4 4 4 5 1 4 1 2 1 4 4 4 5 3 4 4 1 2 4 4 1 2
## [963] 3 3 1 4 5 4 4 4 3 2 1 3 3 3 4 3 4 1 2 4 4 3 4 1 4 1 3 5 4 4 1 1 5 4 4 2 4
## [1000] 4 4 4 1 2 4 4 4 4 4 5 4 4 2 4 4 4 3 2 2 3 4 2 4 4 4 4 5 5 4 4 5 4 4 4 2 5
## [1037] 1 2 4 3 4 4 1 4 4 3 2 1 5 1 4 1 4 2 5 4 1 4 2 1 4 5 2 3 4 1 4 2 4 3 4 3 5
## [1074] 4 1 4 2 3 4 1 4 4 1 1 3 4 1 2 1 4 4 4 3 4 4 1 1 3 2 4 3 4 5 4 5 4 1 1 4 1
## [1111] 4 4 4 3 4 4 3 1 4 4 3 3 4 4 3 4 4 1 4 4 4 5 4 4 1 1 4 1 2 4 3 4 4 1 2 3 2
## [1148] 4 1 1 3 4 1 4 4 2 3 4 4 3 1 4 4 4 1 4 2 1 4 1 4 4 4 4 1 4 4 2 1 4 4 4 5 4
## [1185] 1 1 2 4 2 4 4 3 1 3 4 4 4 4 2 1 3 1 4 1 4 3 4 4 4 2 4 4 1 1 4 1 4 4 4 4 4
## [1222] 4 1 4 3 4 4 4 4 2 1 4 4 4 4 4 1 3 1 3 2 5 1 5 2 4 2 4 3 3 4 4 2 5 4 4 3 1
## [1259] 1 4 1 4 1 4 4 5 4 2 2 4 1 5 4 1 4 2 2 4 4 4 4 4 4 4 1 2 4 1 3 4 4 2 1 1 3
## [1296] 1 5 1 3 4 2 1 4 1 4 4 4 3 1 2 5 4 5 4 4 5 2 4 1 2 2 3 1 2 4 4 4 4 1 1 4 4
## [1333] 4 4 1 1 3 3 2 4 1 3 2 4 1 2 4 1 4 1 1 1 2 4 4 4 1 4 4 4 1 1 4 1 4 4 4 4 4
## [1370] 3 4 4 2 1 4 4 4 4 1 4 4 5 5 1 1 4 4 1 4 4 1 1 4 1 3 4 2 4 5 4 4 4 4 4 5 5
## [1407] 4 4 4 4 4 4 2 4 4 2 4 1 4 1 4 4 4 4 4 4 3 2 1 2 1 5 1 4 2 3 4 1 3 4 4 3 1
## [1444] 1 1 4 4 4 5 1 5 4 3 4 4 4 3 5 4 3 4 4 1 2 1 4 4 2 1 3 1 3 4 1 4 2 1 4 2 4
## [1481] 1 3 3 5 4 4 1 1 1 1 2 2 1 2 4 2 2 4 1 1 4 4 4 3 2 4 4 4 1 2 4 2 4 1 4 1 4
## [1518] 4 4 4 3 1 3 4 1 2 4 1 4 4 4 1 4 4 1 2 5 3 4 4 4 4 5 4 1 4 2 4 4 1 1 1 1 3
## [1555] 4 2 4 4 4 4 3 4 1 4 3 3 4 1 4 4 1 4 3 4 2 4 4 4 1 4 4 2 4 1 2 1 4 4 4 3 1
## [1592] 1 1 3 4 2 4 4 2 4 4 1 5 4 4 2 5 4 4 2 2 4 4 2 4 4 4 1 1 1 2 4 4 4 5 1 4 2
## [1629] 4 1 1 2 4 4 3 4 3 4 4 4 1 5 3 1 4 1 4 4 4 1 4 3 3 4 2 3 5 2 4 4 4 4 4 2 4
## [1666] 4 4 4 4 3 1 2 2 1 3 4 4 4 1 4 1 4 2 5 4 4 1 4 4 1 4 2 4 3 3 4 3 4 5 3 4 4
## [1703] 5 4 3 2 3 4 4 4 4 1 2 4 4 4 2 2 3 1 3 4 4 4 4 4 5 1 2 4 5 5 3 1 1 4 1 4 4
## [1740] 4 4 4 2 2 4 1 1 4 3 4 2 4 4 4 4 1 2 4 4 4 4 4 1 4 4 3 1 4 4 1 4 2 3 4 4 3
## [1777] 4 4 4 1 4 1 2 5 3 4 4 4 1 5 4 3 3 4 5 1 2 2 4 1 2 1 4 1 4 4 5 2 4 1 2 3 4
## [1814] 4 4 1 4 4 4 2 4 5 5 4 3 4 3 1 1 4 4 1 4 3 4 3 3 3 1 4 4 3 5 1 4 1 2 3 1 4
## [1851] 4 4 2 4 2 4 1 4 4 5 2 1 3 2 4 4 5 4 1 4 3 2 4 2 2 4 1 2 4 4 3 2 1 4 4 1 4
## [1888] 4 2 1 4 4 4 2 2 2 3 5 5 4 4 4 4 4 2 3 3 2 4 1 3 2 1 4 1 4 4 2 4 1 1 4 4 5
## [1925] 4 4 2 4 3 2 3 4 4 4 1 3 3 1 3 4 1 3 4 2 5 4 4 4 2 5 3 2 3 1 4 4 1 4 5 2 4
## [1962] 4 4 4 4 2 4 1 4 4 5 4 1 3 4 3 3 4 1 1 1 4 1 4 4 4 4 4 4 2 1 1 1 3 4 3 2 3
## [1999] 4 4 4 4 4 4 4 4 1 5 4 4 4 1 4 1 5 4 5 5 1 2 1 4 2 5 2 4 4 5 4 4 3 2 3 4 1
## [2036] 1 4 4 4 3 5 5 4 5 4 3 2 4 3 4 4 1 2 4 1 2 1 4 4 4 1 3 1 3 3 4 4 4 4 1 2 1
## [2073] 4 2 4 5 1 4 1 4 1 4 4 4 5 4 3 1 5 4 4 4 1 4 1 5 4 4 4 4 5 4 3 5 3 1 4 4 3
## [2110] 1 4 2 1 4 4 4 4 4 4 4 4 1 3 4 4 1 4 4 2 4 4 4 4 4 4 1 1 5 1 1 2 4 4 2 3 2
## [2147] 4 1 5 2 5 1 2 2 1 5 4 4 1 4 4 4 2 1 3 2 4 3 4 4 2 5 4 4 1 5 4 4 1 1 2 4 4
## [2184] 2 4 4 4 1 3 4 3 4 4 4 2 4 4 1 3 4 4 1 1 1 1 4 4 1 4 3 4 5 1 1 1 4
##
## Within cluster sum of squares by cluster:
## [1] 1026.6199 2171.8591 1951.2843 476.0468 625.3122
## (between_SS / total_SS = 59.7 %)
##
## Available components:
##
## [1] "cluster" "centers" "totss" "withinss" "tot.withinss"
## [6] "betweenss" "size" "iter" "ifault"
Customer_Personality_clean <- Customer_Personality %>%
dplyr::select(all_of(vars)) %>%
drop_na() %>%
mutate(cluster = km.res$cluster)
# Ver resultado
head(Customer_Personality_clean)## # A tibble: 6 × 8
## Income MntWines MntFruits MntMeatProducts MntFishProducts MntSweetProducts
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 58138 635 88 546 172 88
## 2 46344 11 1 6 2 1
## 3 71613 426 49 127 111 21
## 4 26646 11 4 20 10 3
## 5 58293 173 43 118 46 27
## 6 62513 520 42 98 0 42
## # ℹ 2 more variables: MntGoldProds <dbl>, cluster <int>
aggregate(Customer_Personality_clean[, vars], by = list(cluster = Customer_Personality_clean$cluster), mean)## cluster Income MntWines MntFruits MntMeatProducts MntFishProducts
## 1 1 61045.62 447.27556 19.415556 132.74222 29.297778
## 2 2 73806.66 502.30389 98.452297 405.93640 132.628975
## 3 3 80736.33 768.66406 45.281250 533.92188 73.011719
## 4 4 34678.18 49.69173 4.775376 24.87688 6.925752
## 5 5 60466.33 509.24540 31.490798 198.13497 40.656442
## MntSweetProducts MntGoldProds
## 1 20.973333 39.02444
## 2 102.060071 91.32862
## 3 47.285156 47.16406
## 4 4.771617 14.84398
## 5 26.950920 160.44172
fviz_cluster(km.res, data = df_scaled,
palette = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07", "#FF6B6B"),
ellipse.type = "euclid",
star.plot = TRUE,
repel = TRUE,
ggtheme = theme_minimal())## [1] 2 4 1 4 1 1 1 4 4 4
## [1] 450 283 256 1064 163
## Income MntWines MntFruits MntMeatProducts MntFishProducts
## 1 0.3495149 0.4215007 -0.1744109 -0.1527252 -0.15232037
## 2 0.8564471 0.5846308 1.8117405 1.0653512 1.73493565
## 3 1.1317282 1.3742487 0.4755803 1.6359933 0.64607741
## 4 -0.6979310 -0.7571264 -0.5423108 -0.6336588 -0.56092631
## 5 0.3265028 0.6052087 0.1290336 0.1388380 0.05513592
## MntSweetProducts MntGoldProds
## 1 -0.147437203 -0.09535402
## 2 1.826818913 0.91407875
## 3 0.493188860 0.06173471
## 4 -0.541907859 -0.56201939
## 5 -0.001898143 2.24791149