4  Análisis de Conglomerados (Cluster)

Segmentación del mercado de dispositivos móviles

Published

December 14, 2025

4.1 Introducción y Objetivos

En este caso, actuamos como el departamento de marketing de una compañía de telecomunicaciones. Disponemos de una encuesta realizada a usuarios sobre sus preferencias y percepciones respecto a dispositivos móviles.

El reto: El mercado no es homogéneo. No todos buscan lo mismo en un móvil. El objetivo: Utilizar el Análisis Cluster para identificar grupos (segmentos) de consumidores con necesidades similares para poder dirigirnos a ellos de forma diferenciada.

El análisis se basará en 25 variables de opinión (p1 a p25) y posteriormente perfilaremos los grupos con variables demográficas y de comportamiento (sexo, edad, financiacion, etc.).


4.2 1. Análisis Descriptivo de la Muestra (Cuestión 1)

Antes de segmentar, debemos entender la materia prima. Analizamos las variables de segmentación (p1 a p25) para verificar su calidad y distribución.

Code
# Seleccionamos las variables de segmentación (p1 a p25)
vars_segmentacion <- data %>% select(p1:p25)

# Mostramos un resumen estadístico interactivo
datatable(psych::describe(vars_segmentacion) %>% select(n, mean, sd, min, max),
          caption = "Descriptivos de las variables de segmentación",
          options = list(pageLength = 10, scrollX = TRUE))

Comentario sobre la muestra: Observamos que las variables parecen estar medidas en una escala homogénea (de 1 a 10). Al observar los mínimos y máximos, confirmamos que comparten rango, por lo que no es estrictamente necesaria la estandarización. Trabajaremos con los datos originales para facilitar la interpretación directa de las medias.

Code
data %>% 
  tab_cells(sexo) %>% 
  tab_stat_cases(label='cases') %>% 
  tab_stat_cpct(label='% cases') %>% 
  tab_last_hstack() %>% 
  tab_pivot %>% 
  set_caption('Sexo')
data %>% 
  tab_cells(financiacion) %>% 
  tab_stat_cases(label='cases') %>% 
  tab_stat_cpct(label='% cases') %>% 
  tab_last_hstack() %>% 
  tab_pivot %>% 
  set_caption('Financiacion')
data %>% 
  tab_cells(sexo) %>% 
  tab_stat_cases(label='cases') %>% 
  tab_stat_cpct(label='% cases') %>% 
  tab_last_hstack() %>% 
  tab_pivot %>% 
  set_caption('Sacrificio')
data %>% 
  tab_cells(tipo) %>% 
  tab_stat_cases(label='cases') %>% 
  tab_stat_cpct(label='% cases') %>% 
  tab_last_hstack() %>% 
  tab_pivot %>% 
  set_caption('Tipo')
data %>% 
  tab_cells(tipo) %>% 
  tab_stat_mean_sd_n() %>% 
  tab_pivot %>% 
  set_caption('Edad del entrevistado')
Sexo
 #Total 
 cases   % cases 
 sexo 
   hombre  54 33.1
   mujer  109 66.9
   #Total cases  163 163
Financiacion
 #Total 
 cases   % cases 
 necesidad de financiación del dispositivo 
   Si  81 49.7
   No  82 50.3
   #Total cases  163 163
Sacrificio
 #Total 
 cases   % cases 
 sexo 
   hombre  54 33.1
   mujer  109 66.9
   #Total cases  163 163
Tipo
 #Total 
 cases   % cases 
 vinculación del dispositivo (operador / libre) 
   Debe ser proporcionado por mi operadora  62 38
   Debe ser terminal libre  101 62
   #Total cases  163 163
Edad del entrevistado
 #Total 
 vinculación del dispositivo (operador / libre) 
   Mean  1.6
   Std. dev.  0.5
   Unw. valid N  163.0

4.3 2. Detección y Tratamiento de Outliers (Cuestiones 2 y 3)

El análisis cluster es muy sensible a los valores atípicos. Usaremos la Distancia de Mahalanobis para detectar patrones de respuesta inusuales.

Code
# 1. Cálculo de la distancia de Mahalanobis
centroides <- colMeans(vars_segmentacion, na.rm = TRUE)
covarianza <- cov(vars_segmentacion, use = "complete.obs")

# Distancia para cada individuo
dist_mahal <- mahalanobis(vars_segmentacion, center = centroides, cov = covarianza)

# 2. Cálculo de la probabilidad (p-valor)
p_values <- pchisq(dist_mahal, df = 25, lower.tail = FALSE)

# 3. Identificación de outliers (Criterio estricto p < 0.001)
umbral <- 0.001
outliers_indices <- which(p_values < umbral)
data_outliers <- data[outliers_indices, ]

# Resultados
print("Número de outliers detectados:", length(outliers_indices))
[1] "Número de outliers detectados:"
Code
if(length(outliers_indices) > 0){
  print("Registros (IDs) considerados atípicos:", data_outliers$id)
} else {
  print("No se han detectado outliers severos bajo el criterio p < 0.001.")
}
[1] "Registros (IDs) considerados atípicos:"

Justificación de la decisión (Cuestión 3):

  • Si se detectan outliers: Procedemos a eliminarlos. Estos individuos tienen patrones de respuesta tan alejados de la norma que podrían distorsionar la formación de los grupos centrales.
  • Si no se detectan: Continuamos con la muestra completa.
Code
# Creamos el dataset limpio
if(length(outliers_indices) > 0){
  data_clean <- data[-outliers_indices, ]
} else {
  data_clean <- data
}
vars_clean <- data_clean %>% select(p1:p25)

4.4 3. Determinación del Número de Grupos (Cluster Jerárquico)

Utilizamos un enfoque exploratorio (Jerárquico con método de Ward) para visualizar la estructura de los datos.

4.4.1 3.1. Dendrograma

Code
# Matriz de distancias
dist_matrix <- dist(vars_clean, method = "euclidean")

# Cluster Jerárquico (Ward)
hc_res <- hclust(dist_matrix, method = "ward.D2")

# Visualización
fviz_dend(hc_res, 
          k = 2, # Previsualizamos un corte de 2 para ver la estructura principal
          cex = 0.5, 
          k_colors = c("#2E9FDF", "#E7B800"),
          color_labels_by_k = TRUE, 
          rect = TRUE,
          main = "Dendrograma de Segmentación (Método Ward)")

4.4.2 3.2. Criterio Estadístico (NbClust)

Para confirmar la decisión visual, utilizamos NbClust que calcula 30 índices diferentes.

Code
# NbClust calcula múltiples índices.
res_nbclust <- NbClust(vars_clean, distance = "euclidean", 
                       min.nc = 2, max.nc = 6, 
                       method = "ward.D2", index = "all")

Code
# Visualización manual robusta de la votación
# Extraemos los votos de la primera fila de Best.nc
votos <- res_nbclust$Best.nc[1, ]

# Preparamos datos y filtramos valores inválidos (0 o NA)
df_votos <- data.frame(n_clusters = as.factor(votos)) %>% 
  filter(n_clusters != "0" & !is.na(n_clusters))

# Gráfico de barras
ggplot(df_votos, aes(x = n_clusters)) +
  geom_bar(fill = "steelblue", color = "white", alpha = 0.8) +
  labs(title = "Número óptimo de clusters según la mayoría de índices",
       subtitle = "Frecuencia de votación entre los índices de NbClust",
       x = "Número de Clusters Propuesto",
       y = "Número de Índices que lo apoyan") +
  theme_minimal()

Decisión: Tanto el dendrograma (que muestra un gran salto vertical antes de dividir en 2) como la votación mayoritaria de los índices estadísticos en NbClust apuntan claramente a una solución. Seleccionamos la solución de 2 grupos como la más robusta y natural para estos datos.


4.5 4. Caracterización de los Grupos (K-Means) (Cuestión 4)

Aplicamos K-Means con \(k=2\) para refinar la asignación y caracterizar los segmentos.

Code
set.seed(123) # Para reproducibilidad
k_optimo <- 2 # Decisión tomada en el paso anterior

# Ejecutamos K-Means
kmeans_res <- kmeans(vars_clean, centers = k_optimo, nstart = 25)

# Añadimos la asignación al dataset
data_clean$cluster <- as.factor(kmeans_res$cluster)

# Tamaño de los grupos
table(data_clean$cluster)

 1  2 
88 65 

4.5.1 Interpretación de los Centroides

Calculamos la media de cada variable en cada grupo para entender qué los diferencia.

Code
# Tabla de medias por grupo
data_clean %>% 
  tab_cells(p1 %to% p25) %>% 
  tab_cols(cluster) %>% 
  tab_stat_mean_sd_n() %>% 
  tab_last_sig_means() %>% # Test de diferencias significativas
  tab_pivot() %>% 
  set_caption("Caracterización de los Segmentos (Medias)")
Caracterización de los Segmentos (Medias)
 cluster 
 1     2 
 A     B 
 calidad de la cámara posterior 
   Mean  8.4    9.1 A
   Std. dev.  1.5    1.2  
   Unw. valid N  88.0    65.0  
 calidad de la cámara frontal 
   Mean  6.9    8.5 A
   Std. dev.  1.9    1.5  
   Unw. valid N  88.0    65.0  
 procesador 
   Mean  7.5    8.8 A
   Std. dev.  1.8    1.3  
   Unw. valid N  88.0    65.0  
 memoria ram 
   Mean  7.5    8.8 A
   Std. dev.  1.6    1.2  
   Unw. valid N  88.0    65.0  
 memoria interna (almacenamiento) 
   Mean  7.7    9.1 A
   Std. dev.  1.6    1.0  
   Unw. valid N  88.0    65.0  
 ranura expansión 
   Mean  5.2    7.2 A
   Std. dev.  2.3    1.7  
   Unw. valid N  88.0    65.0  
 marca 
   Mean  7.1    8.0 A
   Std. dev.  2.3    1.7  
   Unw. valid N  88.0    65.0  
 durabilidad batería 
   Mean  8.4    9.4 A
   Std. dev.  1.5    0.8  
   Unw. valid N  88.0    65.0  
 precio final 
   Mean  8.7    9.1  
   Std. dev.  1.5    1.3  
   Unw. valid N  88.0    65.0  
 tamaño pantalla (pulgadas) 
   Mean  7.4    8.2 A
   Std. dev.  1.7    1.3  
   Unw. valid N  88.0    65.0  
 calidad pantalla (gráfica) 
   Mean  7.7    8.9 A
   Std. dev.  1.6    0.9  
   Unw. valid N  88.0    65.0  
 tamaño del dispositivo 
   Mean  7.3    8.4 A
   Std. dev.  1.8    1.3  
   Unw. valid N  88.0    65.0  
 peso del dispositivo 
   Mean  5.8    7.8 A
   Std. dev.  2.2    1.6  
   Unw. valid N  88.0    65.0  
 sistema operativo 
   Mean  7.8    9.0 A
   Std. dev.  1.6    1.1  
   Unw. valid N  88.0    65.0  
 calidad del audio 
   Mean  7.0    8.8 A
   Std. dev.  1.9    1.1  
   Unw. valid N  88.0    65.0  
 disponibilidad inmediata 
   Mean  7.0    8.6 A
   Std. dev.  2.3    1.4  
   Unw. valid N  88.0    65.0  
 dual sim 
   Mean  3.8    6.6 A
   Std. dev.  2.3    2.2  
   Unw. valid N  88.0    65.0  
 banda (4G, 5G, ...) 
   Mean  7.9    8.9 A
   Std. dev.  1.6    1.2  
   Unw. valid N  88.0    65.0  
 diseño del dispositivo 
   Mean  7.6    8.9 A
   Std. dev.  1.8    1.2  
   Unw. valid N  88.0    65.0  
 waterproof (resistencia al agua) 
   Mean  3.8    7.5 A
   Std. dev.  2.0    1.8  
   Unw. valid N  88.0    65.0  
 gps 
   Mean  7.2    8.7 A
   Std. dev.  2.1    1.5  
   Unw. valid N  88.0    65.0  
 radio 
   Mean  3.7    6.4 A
   Std. dev.  2.2    2.3  
   Unw. valid N  88.0    65.0  
 posibilidad de accesorios 
   Mean  5.1    7.9 A
   Std. dev.  2.0    1.4  
   Unw. valid N  88.0    65.0  
 resistencia de la pantalla 
   Mean  7.7    9.0 A
   Std. dev.  2.0    1.5  
   Unw. valid N  88.0    65.0  
 wi-fi 
   Mean  9.4    9.5  
   Std. dev.  1.2    0.8  
   Unw. valid N  88.0    65.0  

Guía para la interpretación (Cuestión 4):

Al analizar las medias, buscamos las diferencias más grandes entre el Grupo 1 y el Grupo 2.

  • Grupo 1: Observamos sus puntuaciones. Ejemplo hipotético: Si tienen medias altas en casi todo, podrían ser los “Usuarios Intensivos” o “Entusiastas”.
  • Grupo 2: Observamos sus puntuaciones. Ejemplo hipotético: Si tienen medias más bajas o centradas solo en precio/básico, podrían ser los “Usuarios Básicos” o “Pragmáticos”.

4.6 5. Perfilado de los Segmentos (Cuestión 5)

Cruzamos los segmentos con variables externas para definir el perfil del consumidor.

4.6.1 5.1. Perfilado con Variables Categóricas

Analizamos sexo, financiacion, tipo y sacrificio.

Code
# Tabla cruzada con porcentajes columna y test Chi-cuadrado
data_clean %>% 
  tab_cells(sexo, financiacion, tipo, sacrificio) %>% 
  tab_cols(total(), cluster) %>% 
  tab_stat_cpct() %>% 
  tab_last_sig_cell_chisq() %>% 
  tab_pivot() %>% 
  set_caption("Perfilado Demográfico y de Comportamiento (%)")
Perfilado Demográfico y de Comportamiento (%)
 #Total     cluster 
   1   2 
 sexo 
   1  34.6    36.4   32.3  
   2  65.4    63.6   67.7  
   #Total cases  153    88   65  
 necesidad de financiación del dispositivo 
   1  51.6    46.6   58.5  
   2  48.4    53.4   41.5  
   #Total cases  153    88   65  
 vinculación del dispositivo (operador / libre) 
   1  39.9    30.7 < 52.3 >
   2  60.1    69.3 > 47.7 <
   #Total cases  153    88   65  
 sacrificio prestaciones 
   1  11.1    8.0   15.4  
   2  35.3    28.4   44.6  
   4  49.7    60.2 > 35.4 <
   5  3.9    3.4   4.6  
   #Total cases  153    88   65  

4.6.2 5.2. Perfilado con Variables Métricas

Analizamos la edad.

Code
data_clean %>% 
  tab_cells(edad) %>% 
  tab_cols(cluster) %>% 
  tab_stat_mean_sd_n() %>% 
  tab_last_sig_means() %>% 
  tab_pivot() %>% 
  set_caption("Perfilado por Edad (Media)")
Perfilado por Edad (Media)
 cluster 
 1     2 
 A     B 
 edad 
   Mean  24.7    25.5 
   Std. dev.  3.6    5.2 
   Unw. valid N  88.0    65.0 

Conclusiones del Perfilado (Cuestión 5):

Redactamos las conclusiones finales combinando la caracterización y el perfil.

  • Ejemplo: “El Grupo 1 está significativamente más dispuesto a financiar el terminal y muestra una mayor proporción de contratos de permanencia.”
  • Ejemplo: “El Grupo 2 tiene una media de edad ligeramente superior y prefiere terminales libres sin ataduras.”

4.7 Resumen Final

Hemos logrado segmentar la muestra en 2 grupos claramente diferenciados. 1. Hemos validado la calidad de los datos y eliminado distorsiones (outliers). 2. Hemos identificado que la estructura natural del mercado es dual (2 segmentos). 3. Hemos caracterizado las necesidades específicas de cada grupo mediante K-Means. 4. Hemos definido el perfil sociodemográfico para activar campañas de marketing dirigidas a cada uno.