A33- Aplicación: Análisis de Clúster (Conglomerados)

UNIVERSIDAD DE EL SALVADOR
FACULTAD DE CIENCIAS ECONÓMICAS
ESCUELA DE ECONOMÍA
CICLO II - 2024
“Aplicación: Análisis de Clúster (Conglomerados)”
Asignatura:
Métodos para el análisis Económico
Grupo teórico:
Gt 03
Docente:
MSF. Carlos Ademir Pérez Alas
Integrantes:
Fátima Lourdes Alas Duarte AD22008
Gabriela Alexandra Belloso Martínez BM22010
Vanessa Iveth López González LG20034
Fátima Alejandra Rivas Alvarado RA22087
Ciudad Universitaria, 9 de Enero de 2025

Datos

library(readxl)
library(kableExtra)

Datos_3_3_Caso <- read_excel("C:\\Users\\MINEDUCYT\\Downloads\\a33.xlsx", 
    col_types = c("text", "numeric", "numeric", 
        "numeric", "numeric", "numeric", 
        "numeric"))

kable(Datos_3_3_Caso)
ce.AA. Automovil TV_color Video Microondas Lavavajillas Telefono
España 69.0 97.6 62.4 32.3 17.0 85.2
Andalucía 66.7 98.0 82.7 24.1 12.7 74.7
Aragón 67.2 97.5 56.8 43.4 20.6 88.4
Asturias 63.7 95.2 52.1 24.4 13.3 88.1
Baleares 71.9 98.8 62.4 29.8 10.1 87.9
Canarias 72.7 98.6 68.4 27.9 5.8 75.4
Cantabria 63.4 94.9 48.9 36.5 11.2 80.5
Castilla y León 65.8 97.1 47.7 28.1 14.0 85.0
Cast.-La Mancha 61.5 97.3 53.6 21.7 7.1 72.9
Cataluña 70.4 98.1 71.1 36.8 19.8 92.2
Com. Valenciana 72.7 98.4 68.2 26.6 12.1 84.4
Extremadura 60.5 97.7 43.7 20.7 11.7 67.1
Galicia 65.5 91.3 42.7 13.5 14.6 85.9
Madrid 74.0 99.4 76.3 53.9 32.3 95.7
Murcia 69.0 98.7 59.3 19.5 12.1 81.4
Navarra 76.4 99.3 60.6 44.0 20.6 87.4
País Vasco 71.3 98.3 61.6 45.7 23.7 94.3
La Rioja 64.9 98.6 54.4 44.4 17.6 83.4

Obtención de Outliers

# para manipulación de datos
library(dplyr)

# Seleccionar las columnas específicas relacionadas con posesiones
Datos.NbClust <- Datos_3_3_Caso[, c("Automovil", "TV_color", "Video", "Microondas", "Lavavajillas", "Telefono")]

# Calcular la media de cada columna seleccionada
mean <- colMeans(Datos.NbClust)

# Calcular la matriz de covarianza de las columnas seleccionadas
Sx <- cov(Datos.NbClust)

# Calcular la distancia de Mahalanobis para cada observación
# Usando las medias y la matriz de covarianza
D2 <- mahalanobis(Datos.NbClust, mean, Sx, inverted = FALSE)

# Calcular los p-valores asociados a las distancias de Mahalanobis
# Utilizando la distribución chi-cuadrado con 6 grados de libertad
pvalue <- pchisq(D2, df = 6, lower.tail = FALSE)

# Crear un data frame con las distancias de Mahalanobis y sus p-valores
data0 <- data.frame(D2, pvalue)

# Agregar la columna "ce.AA." del data frame original al nuevo data frame
data0 <- cbind(data0, Datos_3_3_Caso$ce.AA.)

# Cambiar los nombres de las columnas del nuevo data frame
names(data0) <- c("D2", "pvalue", "ce.AA.")

# Reordenar las columnas para que estén en el orden deseado
data0 <- select(data0, ce.AA., D2, pvalue)

# Generar una tabla con estilo clásico usando kableExtra
kable_classic(kable(data0))
ce.AA. D2 pvalue
España 0.1942916 0.9998579
Andalucía 10.8730938 0.0923787
Aragón 1.8915174 0.9294003
Asturias 4.5023193 0.6090299
Baleares 5.2650294 0.5102979
Canarias 7.9285965 0.2433813
Cantabria 8.4355298 0.2078993
Castilla y León 2.4538025 0.8736016
Cast.-La Mancha 3.4548550 0.7499660
Cataluña 2.9928500 0.8097437
Com. Valenciana 2.4734149 0.8714310
Extremadura 10.5693417 0.1026338
Galicia 13.3605784 0.0376542
Madrid 8.2156145 0.2227287
Murcia 5.0545122 0.5368408
Navarra 7.7465563 0.2572655
País Vasco 2.3712253 0.8825921
La Rioja 4.2168713 0.6473541

Método Jerárquicos

# Calcular la matriz de distancias euclidianas entre las observaciones
# Basado en las columnas seleccionadas relacionadas con posesiones
matriz.dis.euclid.caso3 <- dist(Datos_3_3_Caso[, c("Automovil", "TV_color", "Video", "Microondas", "Lavavajillas", "Telefono")], method = "euclidean", diag = TRUE)

# Realizar el agrupamiento jerárquico utilizando el método de Ward.D2
hclust.ward.caso3 <- hclust(matriz.dis.euclid.caso3, method = "ward.D2")

# Graficar el dendrograma para el método Ward.D2
# Las etiquetas corresponden a la columna "ce.AA." del data frame original
plot(hclust.ward.caso3, labels = Datos_3_3_Caso$ce.AA.)

# Realizar el agrupamiento jerárquico utilizando el método de promedio (average linkage)
hclust.average.caso3 <- hclust(matriz.dis.euclid.caso3, method = "average")

# Graficar el dendrograma para el método promedio
plot(hclust.average.caso3, labels = Datos_3_3_Caso$ce.AA.)

# (Ejemplo comentado de cómo convertir los resultados en un data frame)
# data.frame(hclust.average.caso3[2:1]) 

# Realizar el agrupamiento jerárquico utilizando el método completo (complete linkage)
hclust.complete.caso3 <- hclust(matriz.dis.euclid.caso3, method = "complete")

# Graficar el dendrograma para el método completo
plot(hclust.complete.caso3, labels = Datos_3_3_Caso$ce.AA.)

# Realizar el agrupamiento jerárquico utilizando el método de enlace simple (single linkage)
hclust.single.caso3 <- hclust(matriz.dis.euclid.caso3, method = "single")

# Graficar el dendrograma para el método de enlace simple
plot(hclust.single.caso3, labels = Datos_3_3_Caso$ce.AA.)

# Realizar el agrupamiento jerárquico utilizando el método de centroide
hclust.centroid.caso3 <- hclust(matriz.dis.euclid.caso3, method = "centroid")

# Graficar el dendrograma para el método de centroide
plot(hclust.centroid.caso3, labels = Datos_3_3_Caso$ce.AA.)

# Cargar la librería NbClust para análisis de agrupamiento
library(NbClust)

# Seleccionar las columnas relevantes del data frame para el análisis de agrupamiento
Datos.NbClust <- Datos_3_3_Caso[, c("Automovil", "TV_color", "Video", "Microondas", "Lavavajillas", "Telefono")]

# Aplicar el método NbClust para determinar el número óptimo de clústeres
# Se utiliza la distancia euclidiana para calcular las distancias
# El número de clústeres evaluados varía entre 2 y 15
# El método de agrupamiento utilizado es Ward.D2
# El índice "alllong" evalúa múltiples criterios para determinar la calidad del agrupamiento
res.wardD2 <- NbClust(Datos.NbClust, distance = "euclidean", 
                      min.nc = 2, max.nc = 15, 
                      method = "ward.D2", index = "alllong")

## *** : The Hubert index is a graphical method of determining the number of clusters.
##                 In the plot of Hubert index, we seek a significant knee that corresponds to a 
##                 significant increase of the value of the measure i.e the significant peak in Hubert
##                 index second differences plot. 
## 

## *** : The D index is a graphical method of determining the number of clusters. 
##                 In the plot of D index, we seek a significant knee (the significant peak in Dindex
##                 second differences plot) that corresponds to a significant increase of the value of
##                 the measure. 
##  
## ******************************************************************* 
## * Among all indices:                                                
## * 6 proposed 2 as the best number of clusters 
## * 9 proposed 3 as the best number of clusters 
## * 2 proposed 4 as the best number of clusters 
## * 1 proposed 7 as the best number of clusters 
## * 1 proposed 13 as the best number of clusters 
## * 8 proposed 15 as the best number of clusters 
## 
##                    ***** Conclusion *****                            
##  
## * According to the majority rule, the best number of clusters is  3 
##  
##  
## *******************************************************************
# Dividir las observaciones en 2 grupos usando el dendrograma Ward.D2
# `hclust.ward.caso3` contiene el agrupamiento jerárquico basado en el método Ward.D2
# `k = 2` indica que se deben formar 2 grupos
# `h = NULL` indica que no se especifica un nivel de corte basado en la altura
grupo.ward <- cutree(hclust.ward.caso3, k = 2, h = NULL)

# Combinar la información del agrupamiento con los datos originales
# Se añade la variable `grupo.ward` al data frame original `Datos_3_3_Caso`
datos.caso3.grupos <- cbind(Datos_3_3_Caso, grupo.ward)

# Eliminar la columna `ce.AA.` del nuevo data frame, ya que no es relevante para este análisis
datos.caso3.grupos$ce.AA. <- NULL

# Calcular el promedio de cada variable en los grupos formados
# `aggregate()` agrupa los datos según la variable `grupo.ward` y calcula la media
# `round()` redondea los resultados a 2 decimales
round(aggregate(datos.caso3.grupos, list(grupo.ward), mean), 2) -> datos.caso3

# Mostrar el data frame resultante con los promedios de cada grupo
print(datos.caso3)
##   Group.1 Automovil TV_color Video Microondas Lavavajillas Telefono grupo.ward
## 1       1     66.87    96.97 57.68      25.42        11.81    80.71          1
## 2       2     70.70    98.53 63.47      44.70        22.43    90.23          2
datos_kmeans <- Datos_3_3_Caso[, -1] 

c1<-c(66.87,96.82,56.01 ,25.43,11.81,80.71) 
c2<-c(70.70,98.53,63.47,44.70,22.43,90.23) 

set.seed(123)
solucion <- kmeans(datos_kmeans, centers = rbind(c1, c2)) |> print( )
## K-means clustering with 2 clusters of sizes 12, 6
## 
## Cluster means:
##   Automovil TV_color    Video Microondas Lavavajillas Telefono
## 1  66.86667 96.96667 57.67500     25.425     11.80833 80.70833
## 2  70.70000 98.53333 63.46667     44.700     22.43333 90.23333
## 
## Clustering vector:
##  [1] 1 1 2 1 1 1 1 1 1 2 1 1 1 2 1 2 2 2
## 
## Within cluster sum of squares by cluster:
## [1] 2813.5567  848.3533
##  (between_SS / total_SS =  40.6 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"

Método no Jerárquicos

# Realizar agrupamiento jerárquico utilizando el método Ward.D2
# `matriz.dis.euclid.caso3` contiene las distancias euclidianas calculadas previamente entre las observaciones
hclust.ward.caso3 <- hclust(matriz.dis.euclid.caso3, method = "ward.D2")

# Graficar el dendrograma resultante del agrupamiento jerárquico
# Las etiquetas (`labels`) corresponden a los valores de la columna `ce.AA.` del conjunto de datos original
plot(hclust.ward.caso3, labels = Datos_3_3_Caso$ce.AA.)

# Dividir las observaciones en 2 grupos basándose en el dendrograma
# `cutree()` asigna cada observación a uno de los 2 grupos formados al cortar el dendrograma
groups <- cutree(hclust.ward.caso3, k = 2)

# Dibujar rectángulos en el dendrograma alrededor de los dos grupos formados
# `rect.hclust()` destaca visualmente los clústeres en el dendrograma
# `k = 2` indica que se deben dibujar rectángulos alrededor de 2 grupos
# `border = "red"` especifica que los rectángulos deben tener un borde rojo
rect.hclust(hclust.ward.caso3, k = 2, border = "green")

# Realizar agrupamiento jerárquico utilizando el método de enlace completo ("complete linkage")
# `matriz.dis.euclid.caso3` es la matriz de distancias euclidianas entre las observaciones
hclust.complete.caso3 <- hclust(matriz.dis.euclid.caso3, method = "complete")

# Graficar el dendrograma resultante del agrupamiento jerárquico
# Las etiquetas (`labels`) corresponden a la columna `ce.AA.` del conjunto de datos original
plot(hclust.complete.caso3, labels = Datos_3_3_Caso$ce.AA.)

# Dividir las observaciones en 2 grupos basándose en el dendrograma
# `cutree()` asigna cada observación a uno de los 2 grupos formados al cortar el dendrograma
groups <- cutree(hclust.complete.caso3, k = 2)

# Dibujar rectángulos en el dendrograma alrededor de los dos grupos formados
# `rect.hclust()` añade rectángulos para resaltar visualmente los clústeres
# `k = 2` indica que se deben formar 2 grupos
# `border = "red"` especifica que el borde de los rectángulos debe ser rojo
rect.hclust(hclust.complete.caso3, k = 2, border = "green")

# Asignamos los datos a una nueva variable para trabajar con ellos
DatosCaso3.1b <- Datos.NbClust

# Realizamos el agrupamiento no jerárquico utilizando el método de k-means
# `kmeans()` forma 2 clústeres (especificado por el parámetro `centers = 2`)
kmeans.caso3.1 <- kmeans(DatosCaso3.1b, 2)

# Calculamos las medias de las variables en cada clúster formado
# `aggregate()` agrupa los datos según el clúster asignado y calcula la media (`FUN=mean`) para cada grupo
aggregate(DatosCaso3.1b, by = list(kmeans.caso3.1$cluster), FUN = mean)
##   Group.1 Automovil TV_color    Video Microondas Lavavajillas Telefono
## 1       1  66.86667 96.96667 57.67500     25.425     11.80833 80.70833
## 2       2  70.70000 98.53333 63.46667     44.700     22.43333 90.23333
# Añadimos la pertenencia de cada observación a los clústeres formados al conjunto de datos original
# Esto permite analizar los resultados del agrupamiento junto con las variables originales
DatosCaso3.1b <- cbind(DatosCaso3.1b, Cluster = kmeans.caso3.1$cluster)
# Cargamos la librería `psych` para realizar análisis estadísticos y pruebas
library(psych)

# Añadimos la asignación de clúster a los datos
# `kmeans.caso3.1$cluster` contiene los grupos formados por el modelo k-means
# Unimos estos grupos al conjunto de datos original `DatosCaso3.1b` para poder analizarlos posteriormente
DatosCaso3.1b <- data.frame(DatosCaso3.1b, kmeans.caso3.1$cluster)

# Extraemos el vector de clústeres asignados a cada observación
kmeans.caso3.1.cluster <- kmeans.caso3.1$cluster

# Realizamos una prueba t para comparar las medias de la variable `Automovil`
# Según los dos grupos formados por el k-means (utilizando `kmeans.caso3.1.cluster`)
# `t.test()` evalúa si hay una diferencia significativa en las medias de `Automovil` entre los dos clústeres
t.test(Automovil ~ kmeans.caso3.1.cluster, data = DatosCaso3.1b)
## 
##  Welch Two Sample t-test
## 
## data:  Automovil by kmeans.caso3.1.cluster
## t = -1.8106, df = 10.091, p-value = 0.1
## alternative hypothesis: true difference in means between group 1 and group 2 is not equal to 0
## 95 percent confidence interval:
##  -8.5449256  0.8782589
## sample estimates:
## mean in group 1 mean in group 2 
##        66.86667        70.70000
library(dplyr)
library(kableExtra)
solucion.cluster<-solucion$cluster
# Calcular las pruebas t
t1 <- t.test(Automovil ~ solucion.cluster, data = Datos.NbClust)
t2 <- t.test(TV_color ~ solucion.cluster, data = Datos.NbClust)
t3 <- t.test(Video ~ solucion.cluster, data = Datos.NbClust)
t4 <- t.test(Microondas ~ solucion.cluster, data = Datos.NbClust)
t5 <- t.test(Lavavajillas ~ solucion.cluster, data = Datos.NbClust)
t6 <- t.test(Telefono ~ solucion.cluster, data = Datos.NbClust)

# Crear un dataframe con los resultados de las pruebas t
resultados.ttest <- data.frame(
  Variable = c("Automovil", "TVcolor", "Video", "Microondas", "Lavavajillas", "Telefono"),
  Grupo_1 = c(t1$estimate[1], t2$estimate[1], t3$estimate[1], t4$estimate[1], t5$estimate[1], t6$estimate[1]),
  Grupo_2 = c(t1$estimate[2], t2$estimate[2], t3$estimate[2], t4$estimate[2], t5$estimate[2], t6$estimate[2]),
  # Aplica la función abs() para asegurarte de que las estadísticas t sean siempre positivas
  Pruebas_t = c(abs(t1$statistic), abs(t2$statistic), abs(t3$statistic), abs(t4$statistic), abs(t5$statistic), abs(t6$statistic))
)

# Mostrar los resultados con kable
head(resultados.ttest) %>%
  kable(caption = "Significatividad de las diferencias entre los perfiles de los conglomerados", 
        align = "c", digits = 2) %>%
  kable_classic(html_font = "Times New Roman", font_size = 14) %>%
  kable_styling()
Significatividad de las diferencias entre los perfiles de los conglomerados
Variable Grupo_1 Grupo_2 Pruebas_t
Automovil 66.87 70.70 1.81
TVcolor 96.97 98.53 2.24
Video 57.68 63.47 1.19
Microondas 25.42 44.70 6.73
Lavavajillas 11.81 22.43 4.61
Telefono 80.71 90.23 3.51
# Cargar las librerías necesarias para el análisis de clustering
library(cluster)   # Para realizar análisis de clusters
library(fpc)       # Para visualizar resultados de clustering

# Realizar una agregación de los datos por el cluster obtenido con k-means
# Se calcula la media de las variables para cada grupo de clusters
aggregate(Datos.NbClust, by = list(kmeans.caso3.1$cluster), FUN = mean)
##   Group.1 Automovil TV_color    Video Microondas Lavavajillas Telefono
## 1       1  66.86667 96.96667 57.67500     25.425     11.80833 80.70833
## 2       2  70.70000 98.53333 63.46667     44.700     22.43333 90.23333
# Crear un nuevo data frame con los datos originales y los clusters obtenidos por k-means
mydata <- data.frame(Datos.NbClust, kmeans.caso3.1$cluster)

# Realizar un análisis de k-means con 2 clusters
fit <- kmeans(mydata, 2)

# Cargar la librería cluster nuevamente (redundante aquí)
library(cluster)

# Visualizar el resultado de los clusters usando un gráfico de dispersión (clusplot)
# Se asignan colores a los clusters, se sombrean las áreas y se etiquetan los puntos
clusplot(mydata, fit$cluster, color = TRUE, shade = TRUE, labels = 2, lines = 0)

# Crear un nuevo data frame con los datos originales y los resultados de los clusters
data5 = data.frame(mydata, fit$cluster)

# Cargar la librería fpc para usar plotcluster
library(fpc)

# Visualizar los clusters utilizando plotcluster
# Este gráfico ayuda a visualizar cómo se agrupan los puntos en función de los clusters
plotcluster(mydata, fit$cluster)