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í:

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.

🎯 Objetivos

Objetivo General

Identificar relaciones de compra entre productos en PlazaVea mediante reglas de asociación para mejorar las estrategias comerciales.

Objetivos Específicos

  1. Preprocesar y explorar los datos transaccionales de PlazaVea.

  2. Aplicar el algoritmo Apriori con umbrales óptimos de soporte, confianza y lift.

  3. Interpretar las reglas encontradas para proponer acciones comerciales.

  4. Visualizar los resultados con gráficos interactivos.

🛒 Base de Datos (50,000 transacciones)

Estructura del Dataset

  • 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)

Objetivo 1: Preprocesar y explorar los datos transaccionales

# -------------------------------
# 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")

  1. 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).

  2. 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).

  3. 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.

  4. 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).

Objetivo 2: Aplicar algoritmo Apriori

# 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:

# 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

Objetivo 3: Interpretación de Reglas

Top 5 Reglas con Mayor Lift

# 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

Interpretación Comercial de Cada Regla

1. {Carne, Huevos, Leche} → {Harina}

  • 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.

2. {Gaseosa, Pescado, Queso} → {Leche}

  • 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.

3. {Galletas, Pan, Papel Higiénico} → {Yogurt}

  • 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).

4. {Café, Detergente, Pescado} → {Fruta}

  • 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.

Análisis Comparativo

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:

  1. Todas las reglas tienen métricas similares, lo que sugiere un patrón consistente en los datos.

  2. El lift > 1.4 indica asociaciones reales (no aleatorias), pero no extraordinariamente fuertes.

  3. La confianza ~32% significa que estas combinaciones predicen el producto consecuente mejor que el azar, pero con margen de mejora.

Objetivo 4: Visualización

# Visualización específica
plot(mejores_reglas, method = "graph", engine = "htmlwidget")