Tema: “Identificación de patrones de compra en supermercados usando el algoritmo Apriori”
PlazaVea, una cadena de supermercados líder en Perú, desea optimizar su estrategia de cross-selling (ventas cruzadas) y la disposición de productos en sus tiendas. Para ello, necesita identificar qué productos se compran juntos con mayor frecuencia y así:
Mejorar la ubicación de productos en góndolas.
Diseñar promociones combinadas efectivas.
Reducir el stock de productos con baja asociación.
Se utilizará el algoritmo Apriori en R para analizar un dataset de 50,000 transacciones y descubrir reglas de asociación relevantes. Utiliza el archivo transacciones_plazavea.csv.
Identificar relaciones de compra entre productos en PlazaVea mediante reglas de asociación para mejorar las estrategias comerciales.
Preprocesar y explorar los datos transaccionales de PlazaVea.
Aplicar el algoritmo Apriori con umbrales óptimos de soporte, confianza y lift.
Interpretar las reglas encontradas para proponer acciones comerciales.
Visualizar los resultados con gráficos interactivos.
ID_transacción: Número único por compra.
Productos: Lista de artículos comprados en cada transacción.
# -------------------------------
# PASO 1: INSTALACIÓN DE PAQUETES
# -------------------------------
# install.packages("arules")
# install.packages("arulesViz")
# install.packages("tidyverse")
# install.packages("readr")
library(arules)
## Warning: package 'arules' was built under R version 4.4.3
## Cargando paquete requerido: Matrix
##
## Adjuntando el paquete: 'arules'
## The following objects are masked from 'package:base':
##
## abbreviate, write
library(arulesViz)
## Warning: package 'arulesViz' was built under R version 4.4.3
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.4.3
## Warning: package 'ggplot2' was built under R version 4.4.3
## Warning: package 'tibble' was built under R version 4.4.2
## Warning: package 'tidyr' was built under R version 4.4.3
## Warning: package 'readr' was built under R version 4.4.3
## Warning: package 'purrr' was built under R version 4.4.3
## Warning: package 'dplyr' was built under R version 4.4.3
## Warning: package 'stringr' was built under R version 4.4.3
## Warning: package 'forcats' was built under R version 4.4.3
## Warning: package 'lubridate' was built under R version 4.4.2
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.1 ✔ tibble 3.2.1
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ✔ purrr 1.0.4
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ tidyr::expand() masks Matrix::expand()
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ✖ tidyr::pack() masks Matrix::pack()
## ✖ dplyr::recode() masks arules::recode()
## ✖ tidyr::unpack() masks Matrix::unpack()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(readr)
# -------------------------------
# PASO 4: IMPORTAR Y TRANSFORMAR A FORMATO TRANSACCIONES
# -------------------------------
# Leer el archivo CSV
transacciones_csv <- read_csv("transacciones_plazavea.csv")
## Rows: 50000 Columns: 2
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): Productos
## dbl (1): ID_Transaccion
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Convertir a formato 'transactions'
transacciones <- strsplit(transacciones_csv$Productos, ",")
transacciones <- as(transacciones, "transactions")
summary(transacciones)
## transactions as itemMatrix in sparse format with
## 50000 rows (elements/itemsets/transactions) and
## 24 columns (items) and a density of 0.2294533
##
## most frequent items:
## Pan Pollo Leche Arroz Carne (Other)
## 11616 11587 11567 11548 11548 217478
##
## element (itemset/transaction) length distribution:
## sizes
## 1 2 3 4 5 6 7 8 9 10
## 5047 4940 4946 5016 4942 5037 5027 5004 5048 4993
##
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.000 3.000 6.000 5.507 8.000 10.000
##
## includes extended item information - examples:
## labels
## 1 Aceite
## 2 Arroz
## 3 Atún
itemFrequencyPlot(transacciones, topN = 10, main = "Top 10 Productos PlazaVea", col = "steelblue")
Estructura de los datos:
50,000 transacciones con 24 productos diferentes.
Densidad 0.229: Indica que aproximadamente el 22.9% de las posibles combinaciones producto-transacción existen (típico en retail).
Productos más frecuentes:
Top 5 productos:
Pan (11,616 apariciones)
Pollo (11,587)
Leche (11,567)
Arroz (11,548)
Carne (11,548)
Estos productos aparecen en ≈23% de las transacciones cada uno (11,500/50,000).
Distribución de tamaño de transacciones:
Las transacciones varían entre 1 y 10 productos.
Distribución uniforme: No hay un tamaño dominante (todos los tamaños entre 1-10 tienen ≈5,000 transacciones cada uno).
Mediana en 6 productos: El 50% de las transacciones tienen 6 o más productos.
Implicaciones comerciales:
Los productos básicos (Pan, Pollo, Leche) son los “traffic drivers”.
La distribución uniforme de tamaños sugiere que no hay un patrón claro de compra (pequeña vs grande).
# 2. Generación de reglas con umbrales adaptados
reglas <- apriori(transacciones,
parameter = list(
support = 0.003, # ≈150 transacciones (0.3%)
confidence = 0.2, # confianza mínima
minlen = 2, # Mínimo 2 productos
maxlen = 4, # Máximo 4 productos
target = "rules"
))
## Apriori
##
## Parameter specification:
## confidence minval smax arem aval originalSupport maxtime support minlen
## 0.2 0.1 1 none FALSE TRUE 5 0.003 2
## maxlen target ext
## 4 rules TRUE
##
## Algorithmic control:
## filter tree heap memopt load sort verbose
## 0.1 TRUE TRUE FALSE TRUE 2 TRUE
##
## Absolute minimum support count: 150
##
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[24 item(s), 50000 transaction(s)] done [0.01s].
## sorting and recoding items ... [24 item(s)] done [0.00s].
## creating transaction tree ... done [0.02s].
## checking subsets of size 1 2 3 4
## Warning in apriori(transacciones, parameter = list(support = 0.003, confidence
## = 0.2, : Mining stopped (maxlen reached). Only patterns up to a length of 4
## returned!
## done [0.06s].
## writing ... [49127 rule(s)] done [0.00s].
## creating S4 object ... done [0.01s].
# Filtrado por lift y confianza
reglas_filtradas <- subset(reglas,
lift > 1.1 &
confidence > 0.25)
Justificación de parámetros:
Soporte 0.3%: Captura patrones significativos sin ruido (considerando la distribución uniforme).
Confianza 20%: Balance entre cantidad y calidad de reglas.
Lift > 1.1: Filtra asociaciones no aleatorias.
# Inspeccionar las reglas actuales
arules::inspect(head(reglas_filtradas,20))
## lhs rhs support confidence coverage
## [1] {Jabón} => {Fruta} 0.05726 0.2536546 0.22574
## [2] {Fruta} => {Jabón} 0.05726 0.2532956 0.22606
## [3] {Jabón} => {Detergente} 0.05888 0.2608310 0.22574
## [4] {Detergente} => {Jabón} 0.05888 0.2580419 0.22818
## [5] {Jabón} => {Aceite} 0.05888 0.2608310 0.22574
## [6] {Aceite} => {Jabón} 0.05888 0.2582456 0.22800
## [7] {Jabón} => {Papel Higiénico} 0.05762 0.2552494 0.22574
## [8] {Papel Higiénico} => {Jabón} 0.05762 0.2521663 0.22850
## [9] {Jabón} => {Azúcar} 0.05852 0.2592363 0.22574
## [10] {Azúcar} => {Jabón} 0.05852 0.2580474 0.22678
## [11] {Jabón} => {Harina} 0.05732 0.2539204 0.22574
## [12] {Harina} => {Jabón} 0.05732 0.2507875 0.22856
## [13] {Jabón} => {Shampoo} 0.05848 0.2590591 0.22574
## [14] {Shampoo} => {Jabón} 0.05848 0.2550593 0.22928
## [15] {Jabón} => {Yogurt} 0.05728 0.2537432 0.22574
## [16] {Yogurt} => {Jabón} 0.05728 0.2504153 0.22874
## [17] {Jabón} => {Verdura} 0.05894 0.2610968 0.22574
## [18] {Verdura} => {Jabón} 0.05894 0.2563277 0.22994
## [19] {Jabón} => {Galletas} 0.05796 0.2567556 0.22574
## [20] {Galletas} => {Jabón} 0.05796 0.2518905 0.23010
## lift count
## [1] 1.122068 2863
## [2] 1.122068 2863
## [3] 1.143093 2944
## [4] 1.143093 2944
## [5] 1.143996 2944
## [6] 1.143996 2944
## [7] 1.117065 2881
## [8] 1.117065 2881
## [9] 1.143118 2926
## [10] 1.143118 2926
## [11] 1.110957 2866
## [12] 1.110957 2866
## [13] 1.129881 2924
## [14] 1.129881 2924
## [15] 1.109309 2864
## [16] 1.109309 2864
## [17] 1.135500 2947
## [18] 1.135500 2947
## [19] 1.115843 2898
## [20] 1.115843 2898
# Filtrar las mejores 4 reglas
mejores_reglas <- head(sort(reglas_filtradas, by = "lift"), 4)
# Convertir a dataframe para análisis
df_reglas <- as(mejores_reglas, "data.frame")
head(df_reglas)
## rules support confidence coverage
## 39555 {Carne,Huevos,Leche} => {Harina} 0.00540 0.3296703 0.01638
## 47004 {Gaseosa,Pescado,Queso} => {Leche} 0.00562 0.3321513 0.01692
## 31474 {Galletas,Pan,Papel Higiénico} => {Yogurt} 0.00530 0.3267571 0.01622
## 14399 {Café,Detergente,Pescado} => {Fruta} 0.00510 0.3215637 0.01586
## lift count
## 39555 1.442380 270
## 47004 1.435771 281
## 31474 1.428509 265
## 14399 1.422471 255
Soporte: 0.54% (270 transacciones)
Confianza: 32.97%
Lift: 1.44
Análisis:
Patrón: Cuando los clientes compran carne, huevos y leche juntos, hay un 33% de probabilidad de que también lleven harina.
Lift 1.44: Esta combinación ocurre 1.44 veces más de lo esperado aleatoriamente.
Contexto: Sugiere preparación de comidas caseras (ej. milanesas, pasteles).
Recomendación:
Crear un “Combo Cocina” con estos 4 productos y ofrecer un 10% de descuento.
Ubicar harina cerca de la sección de refrigerados.
Soporte: 0.56% (281 transacciones)
Confianza: 33.22%
Lift: 1.44
Análisis:
Patrón: Compra típica para reuniones familiares o picnics.
Insight: La leche parece ser un añadido posterior (posiblemente para niños o café).
Recomendación:
Promoción “Día Familiar”: Incluir leche gratis al llevar los otros 3 productos.
Exhibición estratégica: colocar leche cerca de la sección de bebidas.
Soporte: 0.53% (265 transacciones)
Confianza: 32.68%
Lift: 1.43
Análisis:
Patrón: Compra de productos básicos de despensa más un lácteo.
Interpretación: Los clientes que hacen compras “de abastecimiento” añaden yogurt como snack saludable.
Recomendación:
Oferta “Despensa Inteligente”: Descuento progresivo al llevar más productos de la lista.
Posicionar yogurt cerca de la entrada (producto impulso).
Soporte: 0.51% (255 transacciones)
Confianza: 32.16%
Lift: 1.42
Análisis:
Patrón: Combinación inusual que sugiere compras de múltiples propósitos.
Insight: Posiblemente clientes que compran para la semana (productos de limpieza + alimentos).
Recomendación:
Muestra gratis: Ofrecer fruta de temporada al llevar estos productos.
Crear un “Pasillo de Compras Rápidas” con estos items.
Métrica | Promedio | Rango | Interpretación |
---|---|---|---|
Soporte | 0.53% | 0.51-0.56% | Reglas poco frecuentes pero consistentes |
Confianza | 32.41% | 32.16-33.22% | 1 de cada 3 compras con antecedentes incluye el consecuente |
Lift | 1.43 | 1.42-1.44 | Asociaciones positivas pero no fuertes |
Hallazgos clave:
Todas las reglas tienen métricas similares, lo que sugiere un patrón consistente en los datos.
El lift > 1.4 indica asociaciones reales (no aleatorias), pero no extraordinariamente fuertes.
La confianza ~32% significa que estas combinaciones predicen el producto consecuente mejor que el azar, pero con margen de mejora.
# Visualización específica
plot(mejores_reglas, method = "graph", engine = "htmlwidget")