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