Datos

Trabajaremos con los datos del concentrado de hogares de la Encuesta Nacional de Ingresos y Gastos de los Hogares de 2018. Podemos observar que los datos que tenemos están completos. Tomaremos las columnas que tengan datos sociodemográficos y la información sobre ingresos, tomando en cuenta que esto es suficiente ya que los gastos van en función de los ingresos de los hogares.

enigh <- read.csv("C:/Users/luisa/Downloads/concentradohogar.csv", 
                  encoding = "UTF-8-BOM")
sum(colSums(is.na(enigh)))
## [1] 0
ingresos <- enigh[,c(3:5, 9:17, 20:31, 33:52, 56, 109:112)]

K-Medias

Veremos cuantos clusters serían adecuados para nuestros datos basándonos en que tan pequeña es la variación de las observaciones dentro de cada cluster:

library(tidyverse)
library(factoextra)
library(DataExplorer)
library(cluster)
library(reshape)
set.seed(123)

wssplot <- function(data, nc=15, seed=123){
  wss <- c()
  for (i in 1:nc){
    set.seed(seed)
    wss[i] <- kmeans(data, centers = i,nstart = 25, iter.max = 100)$tot.withinss
  }
  plot(1:nc, wss, type="b", pch = 19, frame = FALSE, 
       xlab="Number of clusters K",
       ylab="Total within-clusters sum of squares",
       col = "dodgerblue")
}
wssplot(ingresos, nc = 10)

Podemos ver que después de 4 clusters la variación no cambia significativamente, por lo que decidimos tomar 4 clusters como el valor apropiado.

A continuación probaremos los 4 algoritmos que tenemos disponibles y veremos como separan.

in_kmeans <- kmeans(scale(ingresos), centers = 4, nstart = 25, iter.max = 100,
                    algorithm = "Hartigan-Wong")
in_kmeans2 <- kmeans(scale(ingresos), centers = 4, nstart = 25, iter.max = 100,
                     algorithm = "Lloyd")
in_kmeans3 <- kmeans(scale(ingresos), centers = 4, nstart = 25, iter.max = 100,
                     algorithm = "Forgy")
in_kmeans4 <- kmeans(scale(ingresos), centers = 4, nstart = 25, iter.max = 100,
                     algorithm = "MacQueen")
fviz_cluster(in_kmeans, scale(ingresos)) + labs(title = "Hartigan-Wong")

fviz_cluster(in_kmeans2, scale(ingresos)) + labs(title = "Lloyd")

fviz_cluster(in_kmeans3, scale(ingresos)) + labs(title = "Forgy")

fviz_cluster(in_kmeans4, scale(ingresos)) + labs(title = "MacQueen")

Es muy parecido el resultado de los 4 algoritmos, sin embargo el que presenta una mejor separación es el obtenido usando Hartigan-Wong.

Veamos como se ve la media de cada variable (exceptuando la de ubicación geográfica ya que la media de esta variable no tiene sentido).

kmeans_cluster <-  as.data.frame(scale(ingresos)) %>%
  mutate(Cluster = in_kmeans$cluster) %>%
  group_by(Cluster) %>%
  summarise_all('mean')

info_kmeans <- as.data.frame(t(kmeans_cluster))
info_kmeans$Names <- rownames(info_kmeans)
info_kmeans <- melt(info_kmeans, id.vars = c('Names'))
info_kmeans$variable <- c(rep('Cluster 1', 50), rep('Cluster 2', 50), rep('Cluster 3', 50), rep('Cluster 4', 50))
info_kmeans <- info_kmeans[-c(1,2,51,52,101,102,151,152),]
ggplot(info_kmeans, aes(x = Names, y = value, color = variable, group = variable)) + geom_line() +
    geom_point() + theme(text = element_text(size=12),
                         axis.text.x = element_text(angle=90, hjust=1))

Podemos ver que al menos respecto a la media, los clusters 2, 3 y 4 son muy similares. Además de que el primer cluster agrupa a la gente con mayores ingresos.

Dada esta razón, consideramos que es mejor quedarnos con dos clusters con el objetivo de tener el grupo con mayores ingresos y menor número de integrantes en el hogar, y otro con el de menores ingresos y mayor número de integrantes.

k.means <- kmeans(scale(ingresos), centers = 2, nstart = 25, iter.max = 100,
                  algorithm = "Hartigan-Wong")
fviz_cluster(k.means, scale(ingresos))

kmeans_cluster2 <- as.data.frame(scale(ingresos)) %>%
  mutate(Cluster = k.means$cluster) %>%
  group_by(Cluster) %>%
  summarise_all('mean')
kmeans_cluster2 <- kmeans_cluster2[,c(1,3:50)]

info <- as.data.frame(t(kmeans_cluster2))
info$Names <- rownames(info)
info <- melt(info, id.vars = c('Names'))
info$variable <- c(rep('Cluster 1', 49), rep('Cluster 2',49))
info <- info[-c(1,50),]

ggplot(info, aes(x = Names, y = value, color = variable, group = variable)) + geom_line() +
  geom_point() + theme(text = element_text(size=12),
                       axis.text.x = element_text(angle=90, hjust=1))

Así podemos ver que en este caso ya estan más y mejor separados los datos, donde en uno cluster tenemos a la gente mayores ingresos, mayormente con jefes de familia hombres y gente joven que viven en localidades con mucha gente, mientras que en el otro están mayormente jefas de familia, que reciben más remesas y gente mayor que recibe dinero de su jubilación, además de gente que recibe mayor dinero por transferencias.

Clusterización jerárquica

Para ayudar a la computadora a hacer los cálculos de las distancias escalaremos los datos originales. Además debido al gran número de datos y nuestra limitada memoria RAM, tomaremos una muestra aleatoria de los datos esperando que sea lo suficientemente representativa ya que es solo del 15%, también debido al tiempo en que se tardan en calcular todas las distancias, cargaremos las distancias obtenidas anteriormente.

library(caTools)
ingresos <- scale(ingresos) %>%
  as.data.frame()
split <- sample.split(ingresos$mujeres, SplitRatio = 0.15)
x <- subset(ingresos, split == T)
load('euclidean.Rda')
load('maximum.Rda')
load('manhattan.Rda')
load('minkowski.Rda')
load('datosHC.Rda')

hclust1 <- hclust(euclidean, method = 'complete')
hclust2 <- hclust(maximum, method = 'complete')
hclust3 <- hclust(manhattan, method = 'complete')
hclust4 <- hclust(minkowski, method = 'complete')

summary(euclidean)
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
##   0.2192   5.2450   6.5007   7.6541   8.2829 315.1195
summary(maximum)
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
##   0.1134   2.4567   3.0502   4.2687   4.1889 215.4148
summary(manhattan)
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
##   0.5238  18.6875  24.1670  26.6487  31.2295 659.6193
summary(minkowski)
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
##   0.2192   5.2450   6.5007   7.6541   8.2829 315.1195
plot(hclust1)

plot(hclust2)

plot(hclust3)

plot(hclust4)

Los dendogramas como podemos ver no son muy claros, sin embargo, podemos ver que las distancias más pequeñas se dan usando la norma infinito (maximum), por esto y por nuestro afán de comparar este algoritmo con el de k-medias, utilizaremos 2 clusters.

cut2 <- cutree(hclust2, k = 2)
hier <- mutate(x, cluster = cut2)
count(hier,cluster)
##   cluster     n
## 1       1 11198
## 2       2     1
hier %>%
  summarise_all('mean')
##   ubica_geo  tam_loc est_socio clase_hog sexo_jefe edad_jefe educa_jefe
## 1   15850.3 2.543531  2.057684  2.147692  1.281989  49.89794   5.505402
##   tot_integ  hombres  mujeres  mayores   menores ocupados percep_ing perc_ocupa
## 1  3.591928 1.749531 1.842397 2.834182 0.7577462 1.695687   2.410215   1.648004
##   ing_cor ingtrab  trabajo  sueldos horas_extr comisiones aguinaldo indemtrab
## 1   45691 30461.9 25812.46 22196.68   269.5284   623.4006  1160.681  110.7525
##   otra_rem  negocio  noagrop industria comercio servicios   agrope agricolas
## 1 556.4686 3397.268 2651.491  625.4901 959.2534  1066.747 745.7769  408.3942
##   pecuarios reproducc    pesca otros_trab   rentas utilidad arrenda transfer
## 1  306.0271  11.06171 20.29393   1252.165 2440.628 1939.965 500.663  7987.47
##   jubilacion    becas donativos  remesas bene_gob otros_ing percep_tot
## 1   3541.565 109.2331  1024.228 521.1179  808.088  46.80545   4584.867
##   retiro_inv prestamos otras_perc  cluster
## 1   662.1582  481.1748   1944.549 1.000089

Aquí podemos ver que el algoritmo prácticamente agrupo todas las observaciones en un solo cluster, y que ese cluster acaparador es prácticamente un grupo en medio de los dos que tenemos en k-medias. Veamos que pasa si vamos aumentando los grupos.

cut2 <- cutree(hclust2, k = 3)
hier <- mutate(x, cluster = cut2)
count(hier,cluster)
##   cluster     n
## 1       1 11195
## 2       2     3
## 3       3     1
cut2 <- cutree(hclust2, k = 5)
hier <- mutate(x, cluster = cut2)
count(hier,cluster)
##   cluster     n
## 1       1 11193
## 2       2     3
## 3       3     1
## 4       4     1
## 5       5     1

Vemos que prácticamente sigue pasando lo mismo y es que la division es mala, esto probablemente se debe a que la muestra que tomamos no es representativa y que agarramos muchos datos pertenecientes a un sector, que sería el de las personas en medio de los de ingresos altos y los de ingresos bajos.