A continuación te proporcionaré un código paso a paso para realizar análisis de reglas de asociación en R, junto con su explicación. Este método es muy útil en investigación de mercados para descubrir patrones de compra frecuentes (por ejemplo, “los clientes que compran pan y mantequilla también suelen comprar leche”).
# Instalar los paquetes si no los tienes
#install.packages("arules") # Para reglas de asociación
#install.packages("arulesViz") # Para visualización
#install.packages("tidyverse") # Para manipulación de datos
# Cargar los paquetes
library(arules)
## Cargando paquete requerido: Matrix
##
## Adjuntando el paquete: 'arules'
## The following objects are masked from 'package:base':
##
## abbreviate, write
library(arulesViz)
library(tidyverse)
## ── 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
Necesitamos datos en formato transaccional (lista de compras por transacción). Usaré un conjunto de datos de ejemplo, pero puedes reemplazarlo con tus propios datos.
# Crear datos de ejemplo (transacciones de supermercado)
transacciones <- list(
c("pan", "leche", "huevos"),
c("pan", "mantequilla", "leche", "refresco"),
c("huevos", "refresco"),
c("pan", "mantequilla", "refresco"),
c("huevos", "leche"),
c("pan", "mantequilla", "leche", "huevos"),
c("pan", "mantequilla", "leche"),
c("pan", "leche")
)
transacciones
## [[1]]
## [1] "pan" "leche" "huevos"
##
## [[2]]
## [1] "pan" "mantequilla" "leche" "refresco"
##
## [[3]]
## [1] "huevos" "refresco"
##
## [[4]]
## [1] "pan" "mantequilla" "refresco"
##
## [[5]]
## [1] "huevos" "leche"
##
## [[6]]
## [1] "pan" "mantequilla" "leche" "huevos"
##
## [[7]]
## [1] "pan" "mantequilla" "leche"
##
## [[8]]
## [1] "pan" "leche"
# Convertir a formato transaccional
transacciones <- as(transacciones, "transactions")
Si tienes datos en un dataframe (por ejemplo, CSV), puedes cargarlos así:
# Leer datos desde un archivo CSV
# datos <- read.csv("tu_archivo.csv")
# Convertir a formato transaccional (ajusta según tu estructura de datos)
# transacciones <- as(split(datos[,"producto"], datos[,"id_transaccion"]), "transactions")
# Resumen de las transacciones
summary(transacciones)
## transactions as itemMatrix in sparse format with
## 8 rows (elements/itemsets/transactions) and
## 5 columns (items) and a density of 0.575
##
## most frequent items:
## leche pan huevos mantequilla refresco (Other)
## 6 6 4 4 3 0
##
## element (itemset/transaction) length distribution:
## sizes
## 2 3 4
## 3 3 2
##
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 2.000 2.000 3.000 2.875 3.250 4.000
##
## includes extended item information - examples:
## labels
## 1 huevos
## 2 leche
## 3 mantequilla
# Ver las primeras transacciones
arules::inspect(head(transacciones, 3))
## items
## [1] {huevos, leche, pan}
## [2] {leche, mantequilla, pan, refresco}
## [3] {huevos, refresco}
# Frecuencia de items
itemFrequency(transacciones)
## huevos leche mantequilla pan refresco
## 0.500 0.750 0.500 0.750 0.375
# Gráfico de frecuencia de items (top 5)
itemFrequencyPlot(transacciones, topN = 5, main = "Productos más frecuentes")
# Aplicar el algoritmo Apriori
reglas <- apriori(transacciones,
parameter = list(
support = 0.1, # Soporte mínimo (frecuencia relativa)
confidence = 0.6, # Confianza mínima
minlen = 2 # Mínimo de items por regla
))
## Apriori
##
## Parameter specification:
## confidence minval smax arem aval originalSupport maxtime support minlen
## 0.6 0.1 1 none FALSE TRUE 5 0.1 2
## maxlen target ext
## 10 rules TRUE
##
## Algorithmic control:
## filter tree heap memopt load sort verbose
## 0.1 TRUE TRUE FALSE TRUE 2 TRUE
##
## Absolute minimum support count: 0
##
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[5 item(s), 8 transaction(s)] done [0.00s].
## sorting and recoding items ... [5 item(s)] done [0.00s].
## creating transaction tree ... done [0.00s].
## checking subsets of size 1 2 3 4 done [0.00s].
## writing ... [23 rule(s)] done [0.00s].
## creating S4 object ... done [0.00s].
# Resumen de las reglas encontradas
summary(reglas)
## set of 23 rules
##
## rule length distribution (lhs + rhs):sizes
## 2 3 4
## 8 11 4
##
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 2.000 2.000 3.000 2.826 3.000 4.000
##
## summary of quality measures:
## support confidence coverage lift
## Min. :0.125 Min. :0.6000 Min. :0.1250 Min. :0.8889
## 1st Qu.:0.125 1st Qu.:0.7500 1st Qu.:0.1250 1st Qu.:1.1111
## Median :0.250 Median :1.0000 Median :0.3750 Median :1.3333
## Mean :0.288 Mean :0.8775 Mean :0.3533 Mean :1.3130
## 3rd Qu.:0.375 3rd Qu.:1.0000 3rd Qu.:0.5000 3rd Qu.:1.3333
## Max. :0.625 Max. :1.0000 Max. :0.7500 Max. :2.0000
## count
## Min. :1.000
## 1st Qu.:1.000
## Median :2.000
## Mean :2.304
## 3rd Qu.:3.000
## Max. :5.000
##
## mining info:
## data ntransactions support confidence
## transacciones 8 0.1 0.6
## call
## apriori(data = transacciones, parameter = list(support = 0.1, confidence = 0.6, minlen = 2))
Partimos de 8 transacciones,¿cómo se obtuvieron 23 reglas?
Combinatorias posibles:
Con 6 items únicos en tus datos (pan, leche, huevos, mantequilla, refresco, etc., el número de posibles combinaciones (itemsets) es 2⁶ - 1 = 63 posibles conjuntos de items no vacíos.
El algoritmo Apriori evalúa sistemáticamente todas las combinaciones posibles que cumplen con los umbrales de soporte mínimo (0.1 en nuestro caso).
Generación de reglas:
Para cada itemset frecuente (como {pan, leche}), el algoritmo genera todas las posibles reglas (pan → leche y leche → pan) y luego filtra por confianza.
Con solo 3 items en un conjunto, ya puedes generar 6 reglas posibles (A → B, A → C, B → A, etc.).
Tus parámetros actuales:
support = 0.1 # Solo requiere que aparezca en 1 transacción (8*0.1=0.8 → redondeo a 1)
confidence = 0.6 # Umbral relativamente bajo
minlen = 2 # Permite reglas de solo 2 items
Transacciones originales:
# 1: {pan, leche, huevos}
# 2: {pan, mantequilla, leche, refresco}
# 3: {huevos, refresco}
# 4: {pan, mantequilla, refresco}
# 5: {huevos, leche}
# 6: {pan, mantequilla, leche, huevos}
# 7: {pan, mantequilla, leche}
# 8: {pan, leche}
Itemsets frecuentes (con soporte ≥ 0.1):
Pares: {pan,leche} (soporte 5/8), {pan,mantequilla} (3/8), {leche,huevos} (3/8), etc.
Tripletas: {pan,mantequilla,leche} (3/8), etc.
Ejemplo de generación de múltiples reglas:
Solo del itemset {pan, mantequilla, leche} (que aparece en 3
transacciones) se pueden generar:
pan → mantequilla,leche
mantequilla → pan,leche
leche → pan,mantequilla
pan,mantequilla → leche
pan,leche → mantequilla
mantequilla,leche → pan
Aumentar el soporte mínimo:
reglas_filtradas <- apriori(transacciones,
parameter = list(support = 0.3, confidence = 0.7, minlen = 2))
## Apriori
##
## Parameter specification:
## confidence minval smax arem aval originalSupport maxtime support minlen
## 0.7 0.1 1 none FALSE TRUE 5 0.3 2
## maxlen target ext
## 10 rules TRUE
##
## Algorithmic control:
## filter tree heap memopt load sort verbose
## 0.1 TRUE TRUE FALSE TRUE 2 TRUE
##
## Absolute minimum support count: 2
##
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[5 item(s), 8 transaction(s)] done [0.00s].
## sorting and recoding items ... [5 item(s)] done [0.00s].
## creating transaction tree ... done [0.00s].
## checking subsets of size 1 2 3 done [0.00s].
## writing ... [7 rule(s)] done [0.00s].
## creating S4 object ... done [0.00s].
Aumentar la confianza mínima:
reglas_filtradas <- apriori(transacciones,
parameter = list(support = 0.2, confidence = 0.8, minlen = 2))
## Apriori
##
## Parameter specification:
## confidence minval smax arem aval originalSupport maxtime support minlen
## 0.8 0.1 1 none FALSE TRUE 5 0.2 2
## maxlen target ext
## 10 rules TRUE
##
## Algorithmic control:
## filter tree heap memopt load sort verbose
## 0.1 TRUE TRUE FALSE TRUE 2 TRUE
##
## Absolute minimum support count: 1
##
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[5 item(s), 8 transaction(s)] done [0.00s].
## sorting and recoding items ... [5 item(s)] done [0.00s].
## creating transaction tree ... done [0.00s].
## checking subsets of size 1 2 3 done [0.00s].
## writing ... [7 rule(s)] done [0.00s].
## creating S4 object ... done [0.00s].
Filtrar por lift:
reglas_interesantes <- subset(reglas, lift > 1.2)
Aunque solo tengas 8 transacciones, el bajo soporte mínimo (0.1) permite que:
Cualquier itemset que aparezca al menos 1 vez sea considerado (8*0.1=0.8 → redondeo a 1)
Muchas combinaciones aparecen exactamente 1 vez (soporte = 0.125)
# Ver todas las reglas ordenadas por confianza
arules::inspect(sort(reglas, by = "confidence"))
## lhs rhs support confidence
## [1] {mantequilla} => {pan} 0.500 1.0000000
## [2] {leche, refresco} => {mantequilla} 0.125 1.0000000
## [3] {mantequilla, refresco} => {pan} 0.250 1.0000000
## [4] {pan, refresco} => {mantequilla} 0.250 1.0000000
## [5] {leche, refresco} => {pan} 0.125 1.0000000
## [6] {huevos, mantequilla} => {leche} 0.125 1.0000000
## [7] {huevos, mantequilla} => {pan} 0.125 1.0000000
## [8] {huevos, pan} => {leche} 0.250 1.0000000
## [9] {leche, mantequilla} => {pan} 0.375 1.0000000
## [10] {leche, mantequilla, refresco} => {pan} 0.125 1.0000000
## [11] {leche, pan, refresco} => {mantequilla} 0.125 1.0000000
## [12] {huevos, leche, mantequilla} => {pan} 0.125 1.0000000
## [13] {huevos, mantequilla, pan} => {leche} 0.125 1.0000000
## [14] {leche} => {pan} 0.625 0.8333333
## [15] {pan} => {leche} 0.625 0.8333333
## [16] {huevos} => {leche} 0.375 0.7500000
## [17] {mantequilla} => {leche} 0.375 0.7500000
## [18] {mantequilla, pan} => {leche} 0.375 0.7500000
## [19] {refresco} => {mantequilla} 0.250 0.6666667
## [20] {refresco} => {pan} 0.250 0.6666667
## [21] {pan} => {mantequilla} 0.500 0.6666667
## [22] {huevos, leche} => {pan} 0.250 0.6666667
## [23] {leche, pan} => {mantequilla} 0.375 0.6000000
## coverage lift count
## [1] 0.500 1.3333333 4
## [2] 0.125 2.0000000 1
## [3] 0.250 1.3333333 2
## [4] 0.250 2.0000000 2
## [5] 0.125 1.3333333 1
## [6] 0.125 1.3333333 1
## [7] 0.125 1.3333333 1
## [8] 0.250 1.3333333 2
## [9] 0.375 1.3333333 3
## [10] 0.125 1.3333333 1
## [11] 0.125 2.0000000 1
## [12] 0.125 1.3333333 1
## [13] 0.125 1.3333333 1
## [14] 0.750 1.1111111 5
## [15] 0.750 1.1111111 5
## [16] 0.500 1.0000000 3
## [17] 0.500 1.0000000 3
## [18] 0.500 1.0000000 3
## [19] 0.375 1.3333333 2
## [20] 0.375 0.8888889 2
## [21] 0.750 1.3333333 4
## [22] 0.375 0.8888889 2
## [23] 0.625 1.2000000 3
# Ver las top 5 reglas por lift
arules::inspect(head(sort(reglas, by = "lift"), 5))
## lhs rhs support confidence coverage
## [1] {leche, refresco} => {mantequilla} 0.125 1.0000000 0.125
## [2] {pan, refresco} => {mantequilla} 0.250 1.0000000 0.250
## [3] {leche, pan, refresco} => {mantequilla} 0.125 1.0000000 0.125
## [4] {refresco} => {mantequilla} 0.250 0.6666667 0.375
## [5] {mantequilla} => {pan} 0.500 1.0000000 0.500
## lift count
## [1] 2.000000 1
## [2] 2.000000 2
## [3] 2.000000 1
## [4] 1.333333 2
## [5] 1.333333 4
# Filtrar reglas específicas (ejemplo: que contengan "leche")
reglas_leche <- subset(reglas, items %in% "leche")
arules::inspect(reglas_leche)
## lhs rhs support confidence
## [1] {huevos} => {leche} 0.375 0.7500000
## [2] {mantequilla} => {leche} 0.375 0.7500000
## [3] {leche} => {pan} 0.625 0.8333333
## [4] {pan} => {leche} 0.625 0.8333333
## [5] {leche, refresco} => {mantequilla} 0.125 1.0000000
## [6] {leche, refresco} => {pan} 0.125 1.0000000
## [7] {huevos, mantequilla} => {leche} 0.125 1.0000000
## [8] {huevos, leche} => {pan} 0.250 0.6666667
## [9] {huevos, pan} => {leche} 0.250 1.0000000
## [10] {leche, mantequilla} => {pan} 0.375 1.0000000
## [11] {mantequilla, pan} => {leche} 0.375 0.7500000
## [12] {leche, pan} => {mantequilla} 0.375 0.6000000
## [13] {leche, mantequilla, refresco} => {pan} 0.125 1.0000000
## [14] {leche, pan, refresco} => {mantequilla} 0.125 1.0000000
## [15] {huevos, leche, mantequilla} => {pan} 0.125 1.0000000
## [16] {huevos, mantequilla, pan} => {leche} 0.125 1.0000000
## coverage lift count
## [1] 0.500 1.0000000 3
## [2] 0.500 1.0000000 3
## [3] 0.750 1.1111111 5
## [4] 0.750 1.1111111 5
## [5] 0.125 2.0000000 1
## [6] 0.125 1.3333333 1
## [7] 0.125 1.3333333 1
## [8] 0.375 0.8888889 2
## [9] 0.250 1.3333333 2
## [10] 0.375 1.3333333 3
## [11] 0.500 1.0000000 3
## [12] 0.625 1.2000000 3
## [13] 0.125 1.3333333 1
## [14] 0.125 2.0000000 1
## [15] 0.125 1.3333333 1
## [16] 0.125 1.3333333 1
# Gráfico de dispersión de soporte vs confianza
plot(reglas, method = "scatterplot", main = "Soporte vs Confianza")
## To reduce overplotting, jitter is added! Use jitter = 0 to prevent jitter.
# Gráfico de matriz (para reglas pequeñas)
plot(reglas, method = "matrix", measure = "lift")
## Itemsets in Antecedent (LHS)
## [1] "{pan,refresco}" "{leche,pan,refresco}"
## [3] "{leche,refresco}" "{mantequilla,refresco}"
## [5] "{huevos,mantequilla}" "{huevos,pan}"
## [7] "{leche,mantequilla}" "{leche,mantequilla,refresco}"
## [9] "{huevos,leche,mantequilla}" "{huevos,mantequilla,pan}"
## [11] "{pan}" "{leche,pan}"
## [13] "{mantequilla}" "{refresco}"
## [15] "{leche}" "{huevos}"
## [17] "{mantequilla,pan}" "{huevos,leche}"
## Itemsets in Consequent (RHS)
## [1] "{leche}" "{pan}" "{mantequilla}"
# Gráfico de red (visualización más avanzada)
plot(head(sort(reglas, by = "lift"), 10),
method = "graph",
control = list(type = "items"))
## Warning: Unknown control parameters: type
## Available control parameters (with default values):
## layout = stress
## circular = FALSE
## ggraphdots = NULL
## edges = <environment>
## nodes = <environment>
## nodetext = <environment>
## colors = c("#EE0000FF", "#EEEEEEFF")
## engine = ggplot2
## max = 100
## verbose = FALSE
# Convertir reglas a dataframe para exportar
reglas_df <- as(reglas, "data.frame")
reglas_df
## rules support confidence coverage lift
## 1 {refresco} => {mantequilla} 0.250 0.6666667 0.375 1.3333333
## 2 {refresco} => {pan} 0.250 0.6666667 0.375 0.8888889
## 3 {huevos} => {leche} 0.375 0.7500000 0.500 1.0000000
## 4 {mantequilla} => {leche} 0.375 0.7500000 0.500 1.0000000
## 5 {mantequilla} => {pan} 0.500 1.0000000 0.500 1.3333333
## 6 {pan} => {mantequilla} 0.500 0.6666667 0.750 1.3333333
## 7 {leche} => {pan} 0.625 0.8333333 0.750 1.1111111
## 8 {pan} => {leche} 0.625 0.8333333 0.750 1.1111111
## 9 {leche,refresco} => {mantequilla} 0.125 1.0000000 0.125 2.0000000
## 10 {mantequilla,refresco} => {pan} 0.250 1.0000000 0.250 1.3333333
## 11 {pan,refresco} => {mantequilla} 0.250 1.0000000 0.250 2.0000000
## 12 {leche,refresco} => {pan} 0.125 1.0000000 0.125 1.3333333
## 13 {huevos,mantequilla} => {leche} 0.125 1.0000000 0.125 1.3333333
## 14 {huevos,mantequilla} => {pan} 0.125 1.0000000 0.125 1.3333333
## 15 {huevos,leche} => {pan} 0.250 0.6666667 0.375 0.8888889
## 16 {huevos,pan} => {leche} 0.250 1.0000000 0.250 1.3333333
## 17 {leche,mantequilla} => {pan} 0.375 1.0000000 0.375 1.3333333
## 18 {mantequilla,pan} => {leche} 0.375 0.7500000 0.500 1.0000000
## 19 {leche,pan} => {mantequilla} 0.375 0.6000000 0.625 1.2000000
## 20 {leche,mantequilla,refresco} => {pan} 0.125 1.0000000 0.125 1.3333333
## 21 {leche,pan,refresco} => {mantequilla} 0.125 1.0000000 0.125 2.0000000
## 22 {huevos,leche,mantequilla} => {pan} 0.125 1.0000000 0.125 1.3333333
## 23 {huevos,mantequilla,pan} => {leche} 0.125 1.0000000 0.125 1.3333333
## count
## 1 2
## 2 2
## 3 3
## 4 3
## 5 4
## 6 4
## 7 5
## 8 5
## 9 1
## 10 2
## 11 2
## 12 1
## 13 1
## 14 1
## 15 2
## 16 2
## 17 3
## 18 3
## 19 3
## 20 1
## 21 1
## 22 1
## 23 1
# Exportar a CSV
write.csv(reglas_df, "reglas_asociacion.csv", row.names = FALSE)
Soporte (Support): Frecuencia relativa con la que aparece un conjunto de items. Ej: Soporte(pan → leche) = veces que compran pan y leche / total transacciones.
Confianza (Confidence): Probabilidad de que el item consecuente sea comprado dado que se compró el antecedente. Ej: Confianza(pan → leche) = P(leche|pan).
Lift: Mide cuánto más probable es que se compre el consecuente dado el antecedente, comparado con su probabilidad general. Lift > 1 indica asociación positiva.
Ajusta los parámetros: Experimenta con diferentes valores de soporte y confianza según la densidad de tus datos.
Interpreta el lift: Las reglas con lift > 1 son las más interesantes, ya que indican asociaciones reales.
Filtra resultados: No todas las reglas serán útiles, enfócate en las que tienen sentido para tu investigación de mercado.
Contexto de negocio: Siempre valida los hallazgos con tu conocimiento del negocio.