Teoría

El agrupamiento o clustering es una técnica de aprendizaje automático no supervisado que agrupa datos en función de su similitud. En este análisis aplicamos K-Means para segmentar clientes de un supermercado según su comportamiento de compra: frecuencia (cuántas veces compra) y ticket promedio (cuánto gasta en promedio por visita).


Paso 1. Instalar paquetes y llamar librerías

# install.packages("cluster")
# install.packages("ggplot2")
# install.packages("data.table")
# install.packages("factoextra")
# install.packages("readxl")
# install.packages("dplyr")

library(cluster)
library(ggplot2)
library(data.table)
library(factoextra)
library(readxl)
library(dplyr)

Paso 2. Obtener los datos

df_raw <- read_excel("supermarket.xlsx")
## Warning: Expecting numeric in A522063 / R522063C1: got 'A563185'
## Warning: Expecting numeric in A522064 / R522064C1: got 'A563186'
## Warning: Expecting numeric in A522065 / R522065C1: got 'A563187'
head(df_raw)
## # A tibble: 6 × 8
##   BillNo Itemname         Quantity Date                Time                Price
##    <dbl> <chr>               <dbl> <dttm>              <dttm>              <dbl>
## 1 536365 WHITE HANGING H…        6 2010-12-01 00:00:00 1899-12-31 08:26:00  2.55
## 2 536365 WHITE METAL LAN…        6 2010-12-01 00:00:00 1899-12-31 08:26:00  3.39
## 3 536365 CREAM CUPID HEA…        8 2010-12-01 00:00:00 1899-12-31 08:26:00  2.75
## 4 536365 KNITTED UNION F…        6 2010-12-01 00:00:00 1899-12-31 08:26:00  3.39
## 5 536365 RED WOOLLY HOTT…        6 2010-12-01 00:00:00 1899-12-31 08:26:00  3.39
## 6 536365 SET 7 BABUSHKA …        2 2010-12-01 00:00:00 1899-12-31 08:26:00  7.65
## # ℹ 2 more variables: CustomerID <dbl>, Country <chr>

Paso 3. Estadística Descriptiva y Limpieza

str(df_raw)
## tibble [522,064 × 8] (S3: tbl_df/tbl/data.frame)
##  $ BillNo    : num [1:522064] 536365 536365 536365 536365 536365 ...
##  $ Itemname  : chr [1:522064] "WHITE HANGING HEART T-LIGHT HOLDER" "WHITE METAL LANTERN" "CREAM CUPID HEARTS COAT HANGER" "KNITTED UNION FLAG HOT WATER BOTTLE" ...
##  $ Quantity  : num [1:522064] 6 6 8 6 6 2 6 6 6 32 ...
##  $ Date      : POSIXct[1:522064], format: "2010-12-01" "2010-12-01" ...
##  $ Time      : POSIXct[1:522064], format: "1899-12-31 08:26:00" "1899-12-31 08:26:00" ...
##  $ Price     : num [1:522064] 2.55 3.39 2.75 3.39 3.39 7.65 4.25 1.85 1.85 1.69 ...
##  $ CustomerID: num [1:522064] 17850 17850 17850 17850 17850 ...
##  $ Country   : chr [1:522064] "United Kingdom" "United Kingdom" "United Kingdom" "United Kingdom" ...
summary(df_raw)
##      BillNo         Itemname            Quantity       
##  Min.   :536365   Length:522064      Min.   :-9600.00  
##  1st Qu.:547892   Class :character   1st Qu.:    1.00  
##  Median :560603   Mode  :character   Median :    3.00  
##  Mean   :559951                      Mean   :   10.09  
##  3rd Qu.:571892                      3rd Qu.:   10.00  
##  Max.   :581587                      Max.   :80995.00  
##  NA's   :3                                             
##       Date                          Time                    
##  Min.   :2010-12-01 00:00:00   Min.   :1899-12-31 06:20:00  
##  1st Qu.:2011-03-28 00:00:00   1st Qu.:1899-12-31 11:48:00  
##  Median :2011-07-20 00:00:00   Median :1899-12-31 13:37:00  
##  Mean   :2011-07-03 23:15:13   Mean   :1899-12-31 13:36:07  
##  3rd Qu.:2011-10-19 00:00:00   3rd Qu.:1899-12-31 15:30:00  
##  Max.   :2011-12-09 00:00:00   Max.   :1899-12-31 20:18:00  
##                                                             
##      Price              CustomerID       Country         
##  Min.   :-11062.060   Min.   :12346    Length:522064     
##  1st Qu.:     1.250   1st Qu.:13950    Class :character  
##  Median :     2.080   Median :15265    Mode  :character  
##  Mean   :     3.827   Mean   :15317                      
##  3rd Qu.:     4.130   3rd Qu.:16837                      
##  Max.   : 13541.330   Max.   :18287                      
##                       NA's   :134041
cat("Filas originales:", nrow(df_raw), "\n")
## Filas originales: 522064
cat("Valores nulos por columna:\n")
## Valores nulos por columna:
print(colSums(is.na(df_raw)))
##     BillNo   Itemname   Quantity       Date       Time      Price CustomerID 
##          3       1455          0          0          0          0     134041 
##    Country 
##          0
df_clean <- df_raw %>%
  filter(!is.na(CustomerID),
         !is.na(Price),
         !is.na(Quantity),
         Quantity > 0,
         Price > 0)

cat("Filas después de limpieza:", nrow(df_clean), "\n")
## Filas después de limpieza: 387985
cat("Filas eliminadas:", nrow(df_raw) - nrow(df_clean), "\n")
## Filas eliminadas: 134079

Paso 4. Preparar variables por cliente

Se calculan dos variables por cliente:

df_clean <- df_clean %>%
  mutate(Total = Quantity * Price)

df_clientes <- df_clean %>%
  group_by(CustomerID) %>%
  summarise(
    Frecuencia  = n_distinct(BillNo),
    Ticket_Prom = sum(Total) / n_distinct(BillNo)
  ) %>%
  ungroup()

cat("Clientes únicos:", nrow(df_clientes), "\n")
## Clientes únicos: 4296
summary(df_clientes[, c("Frecuencia", "Ticket_Prom")])
##    Frecuencia       Ticket_Prom      
##  Min.   :  1.000   Min.   :    3.45  
##  1st Qu.:  1.000   1st Qu.:  178.30  
##  Median :  2.000   Median :  292.00  
##  Mean   :  4.227   Mean   :  415.62  
##  3rd Qu.:  5.000   3rd Qu.:  426.63  
##  Max.   :209.000   Max.   :84236.25

Paso 5. Escalar los datos

Como Frecuencia y Ticket Promedio están en escalas distintas, se normalizan para que ninguna variable domine el agrupamiento.

datos_escalados <- scale(df_clientes[, c("Frecuencia", "Ticket_Prom")])
summary(datos_escalados)
##    Frecuencia       Ticket_Prom       
##  Min.   :-0.4556   Min.   :-0.228526  
##  1st Qu.:-0.4556   1st Qu.:-0.131582  
##  Median :-0.3144   Median :-0.068543  
##  Mean   : 0.0000   Mean   : 0.000000  
##  3rd Qu.: 0.1092   3rd Qu.: 0.006104  
##  Max.   :28.9132   Max.   :46.473657

Paso 6. Optimizar el número de clusters (Método del Codo)

Se utiliza el método del codo para confirmar el número óptimo de clusters. Se grafica la variación interna (Within Sum of Squares) para cada k y se elige el punto donde la curva “hace codo”, es decir, donde agregar más clusters ya no reduce significativamente la variación.

set.seed(123)
wss <- sapply(1:10, function(k) {
  kmeans(datos_escalados, centers = k, nstart = 10)$tot.withinss
})

plot(1:10, wss,
     type = "b", pch = 19,
     xlab = "Número de clusters k",
     ylab = "Within Sum of Squares (WSS)",
     main = "Optimización de Clusters - Método del Codo")


Paso 7. Generar los 4 clusters

set.seed(123)
clusters <- kmeans(datos_escalados, centers = 4, nstart = 25)
clusters
## K-means clustering with 4 clusters of sizes 18, 2, 371, 3905
## 
## Cluster means:
##   Frecuencia Ticket_Prom
## 1 10.0634766  0.42562849
## 2 -0.3850355 44.51851525
## 3  1.7015081  0.03010348
## 4 -0.2078443 -0.02762272
## 
## Clustering vector:
##    [1] 2 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4
##   [38] 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4
##   [75] 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 3 4 3 4 4 4 4 3 4 4 4 4 3 4 4 4 4 4 4 3 4 4
##  [112] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4
##  [149] 4 4 4 3 4 4 4 4 4 4 4 4 4 4 3 3 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 3 4
##  [186] 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
##  [223] 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 3 4 4 3 3 3 4 4 4 4 4
##  [260] 4 4 4 4 4 4 4 4 4 4 4 4 3 3 4 3 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 3 4 4 4
##  [297] 4 4 4 4 4 4 4 3 1 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
##  [334] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 3 4
##  [371] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4
##  [408] 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4
##  [445] 4 4 4 4 3 4 4 4 4 4 4 4 4 4 1 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 3 4 4
##  [482] 3 4 4 4 4 4 3 3 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 3 4 4 4
##  [519] 4 4 4 4 4 4 4 4 4 3 4 4 4 4 3 4 4 3 4 4 4 1 3 4 4 4 3 4 3 3 4 4 3 4 4 4 4
##  [556] 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4
##  [593] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 3 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4
##  [630] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
##  [667] 4 3 4 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4
##  [704] 4 4 4 4 4 4 3 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
##  [741] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 1 4 4 4 4
##  [778] 4 3 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 3 4
##  [815] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
##  [852] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4
##  [889] 4 4 4 3 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4
##  [926] 4 4 4 3 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4
##  [963] 4 4 4 4 4 4 4 4 4 4 4 1 3 4 4 3 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [1000] 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 3 3 4 4 4 3
## [1037] 4 4 4 4 3 4 4 4 4 4 1 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [1074] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 3
## [1111] 3 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [1148] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 3 4 3
## [1185] 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 3 4 4 4 4 4
## [1222] 4 3 4 4 4 4 4 4 4 4 3 4 4 4 4 3 3 4 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4
## [1259] 3 4 4 3 4 3 4 3 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 3 4 4 4
## [1296] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 3 3 4 3
## [1333] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 3 4
## [1370] 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 3 4 4 4
## [1407] 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [1444] 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 3 4 4 4
## [1481] 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [1518] 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [1555] 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 1 4 4 4 4 4 3 4 4 4 4 4 4 4 4 3 4
## [1592] 4 4 4 4 4 4 4 4 4 4 4 3 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [1629] 4 4 4 4 1 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 1 4 4 4 4
## [1666] 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 3 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 3
## [1703] 4 4 4 4 3 4 3 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 3 3 4 4 4 4 4 4 4 4 4 4 4 4 3
## [1740] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 3 4 4 4 4
## [1777] 4 4 3 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4
## [1814] 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4
## [1851] 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [1888] 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 3 3 4 4 4 4 4 4 4 3 4
## [1925] 4 4 4 1 4 4 4 3 4 3 4 4 4 4 4 4 4 4 4 3 4 4 1 4 4 4 4 4 4 4 4 4 4 4 4 4 3
## [1962] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4
## [1999] 3 4 4 3 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 3 3 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4
## [2036] 4 4 4 4 4 4 4 4 4 3 3 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4
## [2073] 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [2110] 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 3 3 4 4 4 3 4 4 3 4 4 4 4 4 1 4 4 4 4 4 4 4
## [2147] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 3 4 4 4 4 4 4 4 4 4
## [2184] 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [2221] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4
## [2258] 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 3 4 3 4 4 4 4 4 4 4 4 4 3 3 4 4 4 4 4 4 4
## [2295] 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 3 4
## [2332] 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 3 4 3 4 4 4 4
## [2369] 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [2406] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4
## [2443] 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3
## [2480] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 3 4 4 4 4 4 4 4 4 4 4 4
## [2517] 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 3 4 3 4 4 4 4 4 4 4 4
## [2554] 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [2591] 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4
## [2628] 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 1 4 4 4 4 4 4 4 4 4 4 4 4 4 1
## [2665] 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4
## [2702] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [2739] 3 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 3 4 4 4 4 4 4 4 4 4 4
## [2776] 4 4 4 4 4 4 3 3 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4
## [2813] 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [2850] 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 3 4 4 4
## [2887] 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [2924] 4 4 4 4 4 4 3 4 4 4 4 4 3 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 1 4 4 4 3 4 4 4 4
## [2961] 4 4 4 4 4 4 4 4 4 2 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [2998] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 3 4 4 4 4 4 4 4
## [3035] 4 4 4 4 4 4 3 4 4 4 3 4 4 4 4 3 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 3
## [3072] 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 3 4 4 4
## [3109] 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 3 4 3 4 4 3 4 4 4 4 3 4 4 4 4 4 4 4
## [3146] 4 4 4 3 3 3 4 4 4 3 4 3 3 4 4 4 4 4 4 4 4 3 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4
## [3183] 4 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 3 4 4 4 4 4 4 3 4 4 4 3 4 4 3 4
## [3220] 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 3 4 4 3 4 4 4 4 4 4 4 4 4 4 4
## [3257] 4 4 3 4 3 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [3294] 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 3 4 4 4 4 4 4 3 4 3 4 4 4 3 4 4 3 4 4 4 4
## [3331] 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4
## [3368] 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [3405] 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [3442] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4
## [3479] 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [3516] 4 4 4 4 4 4 3 4 3 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 3 4 4 3 4 4 4 4 4 4 4 4 4
## [3553] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 3
## [3590] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4
## [3627] 4 4 4 4 4 4 4 4 3 4 3 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 3 4 3 4 4 4 4 4 4 4 4
## [3664] 4 4 4 3 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 1 4 4 4 4 4 4 4 4 4 4 4 4
## [3701] 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 3 4 4 4 4 4
## [3738] 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [3775] 4 4 4 4 3 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 3 4 4 4 4 4 4
## [3812] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 3 3 4 4 4 4 4 3 4 4 4 4 4 4 4
## [3849] 4 4 4 4 4 3 4 3 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4
## [3886] 4 3 4 3 4 4 4 4 3 4 4 3 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4
## [3923] 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 3 4 4 4 4 3 3 4 4 4 4 4 4 4
## [3960] 4 4 4 4 4 4 4 4 4 4 1 4 4 4 4 3 4 4 4 4 3 3 4 4 4 4 4 4 3 4 4 4 3 4 4 4 4
## [3997] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4
## [4034] 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 3 4 4 3 4 4 4 4 4 3 4 4 3 4 4 4 4 4 4
## [4071] 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [4108] 4 4 4 4 4 4 4 4 3 4 4 3 4 4 4 4 3 4 4 4 3 4 4 3 4 4 4 4 4 4 3 4 3 3 4 4 4
## [4145] 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 1 4 4 4 4 3 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4
## [4182] 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4
## [4219] 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 4 4 4 3 4 3 3 4 4
## [4256] 3 4 4 4 4 4 4 4 4 4 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [4293] 4 4 3 4
## 
## Within cluster sum of squares by cluster:
## [1] 551.477648   7.655128 391.715982 602.771328
##  (between_SS / total_SS =  81.9 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"

Paso 8. Graficar los clusters

fviz_cluster(clusters, data = datos_escalados,
             geom = "point",
             ellipse.type = "convex",
             palette = c("#E41A1C","#377EB8","#4DAF4A","#FF7F00"),
             main = "Segmentación de Clientes - 4 Clusters")


Paso 9. Agregar Clusters a la Base de Datos

df_clientes_cluster <- cbind(df_clientes, Cluster = clusters$cluster)

# Resumen por cluster con valores reales
resumen <- df_clientes_cluster %>%
  group_by(Cluster) %>%
  summarise(
    Clientes    = n(),
    Frec_Prom   = round(mean(Frecuencia), 1),
    Ticket_Prom = round(mean(Ticket_Prom), 2)
  ) %>%
  arrange(Cluster)

print(resumen)
## # A tibble: 4 × 4
##   Cluster Clientes Frec_Prom Ticket_Prom
##     <int>    <int>     <dbl>       <dbl>
## 1       1       18      75.5       1183.
## 2       2        2       1.5      80710.
## 3       3      371      16.3        470.
## 4       4     3905       2.8        366.
med_frec   <- median(resumen$Frec_Prom)
med_ticket <- median(resumen$Ticket_Prom)

resumen <- resumen %>%
  mutate(Nombre = case_when(
    Frec_Prom <  med_frec & Ticket_Prom <  med_ticket ~ "Clientes Inconsistentes",
    Frec_Prom >= med_frec & Ticket_Prom <  med_ticket ~ "Los Botaneros",
    Frec_Prom <  med_frec & Ticket_Prom >= med_ticket ~ "Megadespensa Ocasional",
    Frec_Prom >= med_frec & Ticket_Prom >= med_ticket ~ "Clientes Estrella"
  ))

print(resumen[, c("Cluster", "Frec_Prom", "Ticket_Prom", "Nombre")])
## # A tibble: 4 × 4
##   Cluster Frec_Prom Ticket_Prom Nombre                 
##     <int>     <dbl>       <dbl> <chr>                  
## 1       1      75.5       1183. Clientes Estrella      
## 2       2       1.5      80710. Megadespensa Ocasional 
## 3       3      16.3        470. Los Botaneros          
## 4       4       2.8        366. Clientes Inconsistentes
df_clientes_cluster <- df_clientes_cluster %>%
  left_join(resumen %>% select(Cluster, Nombre), by = "Cluster")

head(df_clientes_cluster)
##   CustomerID Frecuencia Ticket_Prom Cluster                  Nombre
## 1      12346          1  77183.6000       2  Megadespensa Ocasional
## 2      12347          7    615.7143       4 Clientes Inconsistentes
## 3      12349          1   1757.5500       4 Clientes Inconsistentes
## 4      12350          1    334.4000       4 Clientes Inconsistentes
## 5      12352          8    313.2550       4 Clientes Inconsistentes
## 6      12353          1     89.0000       4 Clientes Inconsistentes

Características y Recomendaciones por Cluster

Clusters Finales

Cluster 1 (18 clientes): Frecuencia 75.5, Ticket $1,183 → Alta frecuencia, ticket medio-alto.
Cluster 2 (2 clientes): Frecuencia 1.5, Ticket $80,710 → Outliers / compradores mayoristas.
Cluster 3 (371 clientes): Frecuencia 16.3, Ticket $470 → Frecuencia media-alta, ticket medio.
Cluster 4 (3,905 clientes): Frecuencia 2.8, Ticket $366 → La mayoría, baja frecuencia, ticket bajo.

Cluster 1 – Clientes Estrella (18 clientes | Frecuencia: 75.5 visitas | Ticket promedio: $1,183) Son los clientes más leales del supermercado. Visitan el establecimiento con altísima frecuencia y mantienen un gasto considerable en cada visita. Aunque son pocos, representan un volumen de compra significativo acumulado a lo largo del tiempo. Su comportamiento sugiere que el supermercado es su principal punto de abastecimiento. Se recomienda implementar un programa VIP o membresía exclusiva que reconozca su lealtad con beneficios tangibles como descuentos especiales, acceso anticipado a promociones y atención preferencial. Es fundamental no descuidar a este segmento ya que son los más difíciles de recuperar si deciden cambiar de supermercado.

Cluster 2 – Compradores Mayoristas (2 clientes | Frecuencia: 1.5 visitas | Ticket promedio: $80,710) Son casos atípicos dentro de la base de datos. Van muy pocas veces pero cuando compran el gasto es extraordinariamente alto, lo que sugiere que podrían ser revendedores, negocios pequeños o compradores institucionales. No representan el comportamiento típico de un cliente de supermercado. Se recomienda contactarlos de forma directa y personalizada para entender sus necesidades específicas. Podría ofrecérseles una cuenta empresarial o convenio de compra por volumen con precios preferenciales, lo que podría fidelizarlos e incluso aumentar su frecuencia de visita.

Cluster 3 – Clientes Frecuentes (371 clientes | Frecuencia: 16.3 visitas | Ticket promedio: $470) Son clientes con una frecuencia de visita notable y un gasto moderado por visita. Conocen bien el supermercado y tienen hábitos de compra establecidos. Es el segmento con mayor potencial de crecimiento porque ya tienen el hábito de visitar la tienda, solo falta incentivarlo a gastar un poco más cada vez. Se recomienda enfocarse en aumentar el ticket promedio por visita mediante promociones de productos complementarios, bundles o descuentos por compra mínima. Estrategias como “si llevas esto, el siguiente tiene X% de descuento” funcionan bien con este perfil.

Cluster 4 – Clientes Ocasionales (3,905 clientes | Frecuencia: 2.8 visitas | Ticket promedio: $366) Es el segmento más grande y representa la base de la pirámide. Visitan poco y gastan relativamente poco en cada visita. Probablemente son clientes que no tienen al supermercado como su destino principal de compra, o que solo acuden cuando tienen una necesidad puntual. Se recomienda trabajar en estrategias de reactivación y retención: cupones de descuento para la próxima visita, recordatorios por correo o app, y promociones en productos de primera necesidad que los motiven a regresar con mayor frecuencia. Convertir aunque sea una fracción de este grupo en clientes frecuentes tendría un impacto enorme en los ingresos totales del supermercado.