library(readxl)
# Cargar archivo Excel desde ruta local
ruta <- "C:/Users/rylun/Downloads/top_5_products.xlsx"
df <- read_excel(ruta)
# Vista general
head(df)
## # A tibble: 6 × 26
## Trx_Num Trx_Fecha Origen Sucursal Num_Cliente ID_Inventario Cant
## <dbl> <dttm> <chr> <chr> <dbl> <dbl> <dbl>
## 1 3954 2023-02-25 00:00:00 NOTAS DE… ACA 1049 155001 -2
## 2 46453 2023-02-09 00:00:00 FACTURAS… ACA 1049 155001 2
## 3 46455 2023-02-09 00:00:00 FACTURAS… ACA 7455 155001 40
## 4 46476 2023-02-16 00:00:00 FACTURAS… ACA 4981 155001 30
## 5 46480 2023-02-16 00:00:00 FACTURAS… ACA 7455 155001 60
## 6 46501 2023-02-20 00:00:00 FACTURAS… ACA 2925 155001 5
## # ℹ 19 more variables: Linea <chr>, Especifico <chr>, Canal_Venta <chr>,
## # Tipo_Precio <dbl>, Tipo_Modificador <chr>, Venta <dbl>, Costo_Venta <dbl>,
## # Costo_Devolucion <dbl>, Ajus_Sistema <dbl>, Ajuste_Manual <dbl>,
## # Precio_Lista_Unitario <dbl>, Precio_Final_Unitario <dbl>, Semana <dbl>,
## # Mes <dbl>, Ciudad <chr>, Zona <chr>, Devoluciones <dbl>,
## # Diferencia_Precio <dbl>, Descuento_Porcentaje <dbl>
str(df)
## tibble [32,684 × 26] (S3: tbl_df/tbl/data.frame)
## $ Trx_Num : num [1:32684] 3954 46453 46455 46476 46480 ...
## $ Trx_Fecha : POSIXct[1:32684], format: "2023-02-25" "2023-02-09" ...
## $ Origen : chr [1:32684] "NOTAS DE CREDITO IMPORTADAS" "FACTURAS IMPORTADAS" "FACTURAS IMPORTADAS" "FACTURAS IMPORTADAS" ...
## $ Sucursal : chr [1:32684] "ACA" "ACA" "ACA" "ACA" ...
## $ Num_Cliente : num [1:32684] 1049 1049 7455 4981 7455 ...
## $ ID_Inventario : num [1:32684] 155001 155001 155001 155001 155001 ...
## $ Cant : num [1:32684] -2 2 40 30 60 5 2 1 4 1 ...
## $ Linea : chr [1:32684] "PQU" "PQU" "PQU" "PQU" ...
## $ Especifico : chr [1:32684] "TCG" "TCG" "TCG" "TCG" ...
## $ Canal_Venta : chr [1:32684] "Sucursal" "Sucursal" "Sucursal" "Sucursal" ...
## $ Tipo_Precio : num [1:32684] 1 1 1 1 1 1 1 1 1 1 ...
## $ Tipo_Modificador : chr [1:32684] "CARTA DESCUENTO" "CARTA DESCUENTO" "CARTA DESCUENTO" "CARTA DESCUENTO" ...
## $ Venta : num [1:32684] -1187 1187 21280 15960 31920 ...
## $ Costo_Venta : num [1:32684] 0 1194 23874 17906 35811 ...
## $ Costo_Devolucion : num [1:32684] 958 0 0 0 0 ...
## $ Ajus_Sistema : num [1:32684] -2515 -2515 -2515 -2515 -2515 ...
## $ Ajuste_Manual : num [1:32684] -1083 -1083 -1145 -1145 -1145 ...
## $ Precio_Lista_Unitario: num [1:32684] 4192 4192 4192 4192 4192 ...
## $ Precio_Final_Unitario: num [1:32684] 594 594 532 532 532 ...
## $ Semana : num [1:32684] 8 6 6 7 7 8 8 5 5 5 ...
## $ Mes : num [1:32684] 2 2 2 2 2 2 2 2 2 2 ...
## $ Ciudad : chr [1:32684] "Acapulco" "Acapulco" "Acapulco" "Acapulco" ...
## $ Zona : chr [1:32684] "Sur" "Sur" "Sur" "Sur" ...
## $ Devoluciones : num [1:32684] 1 0 0 0 0 0 0 0 0 0 ...
## $ Diferencia_Precio : num [1:32684] 3598 3598 3660 3660 3660 ...
## $ Descuento_Porcentaje : num [1:32684] 85.8 85.8 87.3 87.3 87.3 ...
library(dplyr)
##
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(ggplot2)
# Agrupar por producto y cliente para sumar ventas
top_clientes_por_producto <- df %>%
group_by(ID_Inventario, Num_Cliente) %>%
summarise(ventas_totales = sum(Venta, na.rm = TRUE), .groups = "drop") %>%
arrange(ID_Inventario, desc(ventas_totales))
# Tomamos los top 5 clientes por cada producto
top5_por_producto <- top_clientes_por_producto %>%
group_by(ID_Inventario) %>%
slice_max(ventas_totales, n = 5) %>%
ungroup()
# Visualización
ggplot(top5_por_producto, aes(x = reorder(Num_Cliente, ventas_totales), y = ventas_totales, fill = as.factor(ID_Inventario))) +
geom_col() +
coord_flip() +
facet_wrap(~ ID_Inventario, scales = "free_y") +
labs(title = "Top 5 clientes por producto", x = "Cliente", y = "Ventas totales", fill = "Producto") +
theme_minimal()

clientes_devoluciones <- df %>%
group_by(Num_Cliente) %>%
summarise(total_devoluciones = sum(Devoluciones, na.rm = TRUE), .groups = "drop") %>%
arrange(desc(total_devoluciones)) %>%
slice_head(n = 10) # Top 10 clientes
ggplot(clientes_devoluciones, aes(x = reorder(Num_Cliente, total_devoluciones), y = total_devoluciones)) +
geom_col(fill = "tomato") +
coord_flip() +
labs(title = "Clientes con más devoluciones", x = "Cliente", y = "Total de devoluciones") +
theme_minimal()

clientes_frecuentes <- df %>%
group_by(Num_Cliente) %>%
summarise(frecuencia = n(), .groups = "drop") %>%
arrange(desc(frecuencia)) %>%
slice_head(n = 10)
ggplot(clientes_frecuentes, aes(x = reorder(Num_Cliente, frecuencia), y = frecuencia)) +
geom_col(fill = "steelblue") +
coord_flip() +
labs(title = "Clientes más frecuentes", x = "Cliente", y = "Número de transacciones") +
theme_minimal()

library(dplyr)
# Paso 1: Calcular cuántas veces cada cliente compró cada producto
compras_cliente_producto <- df %>%
group_by(ID_Inventario, Num_Cliente) %>%
summarise(compras = n(), .groups = "drop")
# Paso 2: Para cada producto, calcular min, max y promedio de esas compras
estadisticas_por_producto <- compras_cliente_producto %>%
group_by(ID_Inventario) %>%
summarise(
min_compras = min(compras),
max_compras = max(compras),
promedio_compras = mean(compras),
.groups = "drop"
)
# Ver resultados
head(estadisticas_por_producto)
## # A tibble: 5 × 4
## ID_Inventario min_compras max_compras promedio_compras
## <dbl> <int> <int> <dbl>
## 1 155001 1 168 10.9
## 2 155002 1 150 8.78
## 3 3678055 1 63 4.15
## 4 3904152 1 120 4.99
## 5 3929788 1 226 11.3
CLUSTERS
Agregar datos por cliente y producto
library(dplyr)
cliente_producto_df <- df %>%
group_by(ID_Inventario, Num_Cliente) %>%
summarise(
frecuencia = n(),
volumen_total = sum(Venta, na.rm = TRUE),
descuento_promedio = mean(Descuento_Porcentaje, na.rm = TRUE),
precio_promedio = mean(Precio_Final_Unitario, na.rm = TRUE),
meses_distintos = n_distinct(Mes),
.groups = "drop"
)
library(dplyr)
library(ggplot2)
# Función que grafica el codo y luego aplica clustering para un producto específico
analizar_producto <- function(prod_id, k_clusters = 3, graficar_codo = TRUE) {
# Filtrar datos del producto
datos_filtrados <- cliente_producto_df %>%
filter(ID_Inventario == prod_id) %>%
select(frecuencia, volumen_total, descuento_promedio, precio_promedio, meses_distintos)
# Escalar
datos_scaled <- scale(datos_filtrados)
# Gráfica del método del codo (opcional)
if (graficar_codo) {
set.seed(123)
wss <- sapply(1:10, function(k){
kmeans(datos_scaled, centers = k, nstart = 10)$tot.withinss
})
plot_df <- data.frame(k = 1:10, wss = wss)
print(
ggplot(plot_df, aes(x = k, y = wss)) +
geom_line(color = "steelblue", size = 1.2) +
geom_point(color = "red", size = 2) +
labs(title = paste("Método del Codo - Producto", prod_id),
x = "Número de Clusters (k)",
y = "Suma de Cuadrados Intra-cluster (WSS)") +
theme_minimal()
)
}
# Clustering con número de clusters predefinido
set.seed(123)
kmeans_modelo <- kmeans(datos_scaled, centers = k_clusters)
# Devolver los datos con cluster asignado
resultado <- cliente_producto_df %>%
filter(ID_Inventario == prod_id) %>%
mutate(cluster = as.factor(kmeans_modelo$cluster))
return(resultado)
}
# ✅ Ejemplo para un producto (con gráfica del codo y k=3)
resultado_155001 <- analizar_producto(155001, k_clusters = 3, graficar_codo = TRUE)
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

resultado_155001 <- analizar_producto(155002, k_clusters = 3, graficar_codo = TRUE)

resultado_155001 <- analizar_producto(3678055, k_clusters = 3, graficar_codo = TRUE)

resultado_155001 <- analizar_producto(3904152, k_clusters = 3, graficar_codo = TRUE)

resultado_155001 <- analizar_producto(3929788, k_clusters = 3, graficar_codo = TRUE)

library(purrr)
## Warning: package 'purrr' was built under R version 4.4.3
# Lista de productos a analizar
productos_objetivo <- c(155001, 155002, 3678055, 3904152, 3929788)
# Aplicar clustering a todos los productos sin graficar codo
clusters_todos <- map_dfr(productos_objetivo, ~analizar_producto(.x, k_clusters = 3, graficar_codo = FALSE))
# Ver los primeros resultados
head(clusters_todos)
## # A tibble: 6 × 8
## ID_Inventario Num_Cliente frecuencia volumen_total descuento_promedio
## <dbl> <dbl> <int> <dbl> <dbl>
## 1 155001 1 3 2660. 91.2
## 2 155001 9 16 6496. 85.7
## 3 155001 16 39 260666 90.0
## 4 155001 27 8 3122. 90.2
## 5 155001 28 3 9408. 90.7
## 6 155001 39 35 161000. 89.2
## # ℹ 3 more variables: precio_promedio <dbl>, meses_distintos <int>,
## # cluster <fct>
ggplot(clusters_todos, aes(x = frecuencia, y = volumen_total, color = cluster)) +
geom_point(alpha = 0.7) +
facet_wrap(~ID_Inventario, scales = "free") +
labs(
title = "Clusters de Clientes por Producto",
x = "Frecuencia de Compra",
y = "Volumen Total de Compra",
color = "Cluster"
) +
theme_minimal() +
scale_color_brewer(palette = "Set2")

Producto 155001
library(ggplot2)
# Elige un producto para visualizar
producto_elegido <- 155001
ggplot(
clusters_todos %>% filter(ID_Inventario == producto_elegido),
aes(x = frecuencia, y = volumen_total, color = cluster)
) +
geom_point(size = 3, alpha = 0.7) +
labs(
title = paste("Clusters de Clientes - Producto", producto_elegido),
x = "Frecuencia de Compra",
y = "Volumen Total de Compra",
color = "Cluster"
) +
theme_minimal() +
scale_color_brewer(palette = "Set1")

ggplot(clusters_todos %>% filter(ID_Inventario == 155001),
aes(x = cluster, y = volumen_total, fill = cluster)) +
geom_boxplot(alpha = 0.8) +
labs(
title = "Distribución del Volumen de Compra por Cluster - Producto 155001",
x = "Cluster",
y = "Volumen Total de Compra"
) +
theme_minimal() +
scale_fill_brewer(palette = "Set3")

# Cambia el ID del producto que quieras analizar
producto_elegido <- 155001
clusters_todos %>%
filter(ID_Inventario == producto_elegido) %>%
group_by(cluster) %>%
summarise(
frecuencia_promedio = mean(frecuencia),
volumen_promedio = mean(volumen_total),
descuento_promedio = mean(descuento_promedio),
precio_promedio = mean(precio_promedio),
meses_distintos_promedio = mean(meses_distintos),
n_clientes = n(),
.groups = "drop"
)
## # A tibble: 3 × 7
## cluster frecuencia_promedio volumen_promedio descuento_promedio
## <fct> <dbl> <dbl> <dbl>
## 1 1 4.46 5601. 83.8
## 2 2 37.1 120328. 89.6
## 3 3 5.06 10803. 90.1
## # ℹ 3 more variables: precio_promedio <dbl>, meses_distintos_promedio <dbl>,
## # n_clientes <int>
Producto 155002
library(ggplot2)
# Elige un producto para visualizar
producto_elegido <- 155002
ggplot(
clusters_todos %>% filter(ID_Inventario == producto_elegido),
aes(x = frecuencia, y = volumen_total, color = cluster)
) +
geom_point(size = 3, alpha = 0.7) +
labs(
title = paste("Clusters de Clientes - Producto", producto_elegido),
x = "Frecuencia de Compra",
y = "Volumen Total de Compra",
color = "Cluster"
) +
theme_minimal() +
scale_color_brewer(palette = "Set1")

ggplot(clusters_todos %>% filter(ID_Inventario == 155002),
aes(x = cluster, y = volumen_total, fill = cluster)) +
geom_boxplot(alpha = 0.8) +
labs(
title = "Distribución del Volumen de Compra por Cluster - Producto 155001",
x = "Cluster",
y = "Volumen Total de Compra"
) +
theme_minimal() +
scale_fill_brewer(palette = "Set3")

# Cambia el ID del producto que quieras analizar
producto_elegido <- 155002
clusters_todos %>%
filter(ID_Inventario == producto_elegido) %>%
group_by(cluster) %>%
summarise(
frecuencia_promedio = mean(frecuencia),
volumen_promedio = mean(volumen_total),
descuento_promedio = mean(descuento_promedio),
precio_promedio = mean(precio_promedio),
meses_distintos_promedio = mean(meses_distintos),
n_clientes = n(),
.groups = "drop"
)
## # A tibble: 3 × 7
## cluster frecuencia_promedio volumen_promedio descuento_promedio
## <fct> <dbl> <dbl> <dbl>
## 1 1 3.47 6741. 90.4
## 2 2 26.8 85826. 89.8
## 3 3 3.29 4671. 86.2
## # ℹ 3 more variables: precio_promedio <dbl>, meses_distintos_promedio <dbl>,
## # n_clientes <int>
Producto 3678055
library(ggplot2)
# Elige un producto para visualizar
producto_elegido <- 3678055
ggplot(
clusters_todos %>% filter(ID_Inventario == producto_elegido),
aes(x = frecuencia, y = volumen_total, color = cluster)
) +
geom_point(size = 3, alpha = 0.7) +
labs(
title = paste("Clusters de Clientes - Producto", producto_elegido),
x = "Frecuencia de Compra",
y = "Volumen Total de Compra",
color = "Cluster"
) +
theme_minimal() +
scale_color_brewer(palette = "Set1")

ggplot(clusters_todos %>% filter(ID_Inventario == 3678055),
aes(x = cluster, y = volumen_total, fill = cluster)) +
geom_boxplot(alpha = 0.8) +
labs(
title = "Distribución del Volumen de Compra por Cluster - Producto 155001",
x = "Cluster",
y = "Volumen Total de Compra"
) +
theme_minimal() +
scale_fill_brewer(palette = "Set3")

# Cambia el ID del producto que quieras analizar
producto_elegido <- 3678055
clusters_todos %>%
filter(ID_Inventario == producto_elegido) %>%
group_by(cluster) %>%
summarise(
frecuencia_promedio = mean(frecuencia),
volumen_promedio = mean(volumen_total),
descuento_promedio = mean(descuento_promedio),
precio_promedio = mean(precio_promedio),
meses_distintos_promedio = mean(meses_distintos),
n_clientes = n(),
.groups = "drop"
)
## # A tibble: 3 × 7
## cluster frecuencia_promedio volumen_promedio descuento_promedio
## <fct> <dbl> <dbl> <dbl>
## 1 1 2.81 21293. 66.3
## 2 2 2.21 15020. 64.2
## 3 3 18.4 222906. 66.1
## # ℹ 3 more variables: precio_promedio <dbl>, meses_distintos_promedio <dbl>,
## # n_clientes <int>
Producto 3904152
library(ggplot2)
# Elige un producto para visualizar
producto_elegido <- 3904152
ggplot(
clusters_todos %>% filter(ID_Inventario == producto_elegido),
aes(x = frecuencia, y = volumen_total, color = cluster)
) +
geom_point(size = 3, alpha = 0.7) +
labs(
title = paste("Clusters de Clientes - Producto", producto_elegido),
x = "Frecuencia de Compra",
y = "Volumen Total de Compra",
color = "Cluster"
) +
theme_minimal() +
scale_color_brewer(palette = "Set1")

ggplot(clusters_todos %>% filter(ID_Inventario == 3904152),
aes(x = cluster, y = volumen_total, fill = cluster)) +
geom_boxplot(alpha = 0.8) +
labs(
title = "Distribución del Volumen de Compra por Cluster - Producto 155001",
x = "Cluster",
y = "Volumen Total de Compra"
) +
theme_minimal() +
scale_fill_brewer(palette = "Set3")

# Cambia el ID del producto que quieras analizar
producto_elegido <- 3904152
clusters_todos %>%
filter(ID_Inventario == producto_elegido) %>%
group_by(cluster) %>%
summarise(
frecuencia_promedio = mean(frecuencia),
volumen_promedio = mean(volumen_total),
descuento_promedio = mean(descuento_promedio),
precio_promedio = mean(precio_promedio),
meses_distintos_promedio = mean(meses_distintos),
n_clientes = n(),
.groups = "drop"
)
## # A tibble: 3 × 7
## cluster frecuencia_promedio volumen_promedio descuento_promedio
## <fct> <dbl> <dbl> <dbl>
## 1 1 2.24 8580. 63.7
## 2 2 3.79 22323. 66.1
## 3 3 36.5 367042. 66.0
## # ℹ 3 more variables: precio_promedio <dbl>, meses_distintos_promedio <dbl>,
## # n_clientes <int>
Producto 3929788
library(ggplot2)
# Elige un producto para visualizar
producto_elegido <- 3929788
ggplot(
clusters_todos %>% filter(ID_Inventario == producto_elegido),
aes(x = frecuencia, y = volumen_total, color = cluster)
) +
geom_point(size = 3, alpha = 0.7) +
labs(
title = paste("Clusters de Clientes - Producto", producto_elegido),
x = "Frecuencia de Compra",
y = "Volumen Total de Compra",
color = "Cluster"
) +
theme_minimal() +
scale_color_brewer(palette = "Set1")

ggplot(clusters_todos %>% filter(ID_Inventario == 3929788),
aes(x = cluster, y = volumen_total, fill = cluster)) +
geom_boxplot(alpha = 0.8) +
labs(
title = "Distribución del Volumen de Compra por Cluster - Producto 155001",
x = "Cluster",
y = "Volumen Total de Compra"
) +
theme_minimal() +
scale_fill_brewer(palette = "Set3")

# Cambia el ID del producto que quieras analizar
producto_elegido <- 3929788
clusters_todos %>%
filter(ID_Inventario == producto_elegido) %>%
group_by(cluster) %>%
summarise(
frecuencia_promedio = mean(frecuencia),
volumen_promedio = mean(volumen_total),
descuento_promedio = mean(descuento_promedio),
precio_promedio = mean(precio_promedio),
meses_distintos_promedio = mean(meses_distintos),
n_clientes = n(),
.groups = "drop"
)
## # A tibble: 3 × 7
## cluster frecuencia_promedio volumen_promedio descuento_promedio
## <fct> <dbl> <dbl> <dbl>
## 1 1 37.6 68014. 61.5
## 2 2 3.95 3532. 39.4
## 3 3 4.17 4875. 59.8
## # ℹ 3 more variables: precio_promedio <dbl>, meses_distintos_promedio <dbl>,
## # n_clientes <int>