1 PRESENTACIÓN DEL ANALISIS

Curso: Minería de Datos
Nivel: Maestría en Estadística
Base: Transacciones_any.xlsx
Naturaleza: Datos simulados

La minería de reglas de asociación permite identificar patrones de aparición conjunta de objetos o atributos en bases de datos transaccionales. Una regla se expresa como \(X \Rightarrow Y\), donde \(X\) e \(Y\) son conjuntos de ítems que no comparten elementos. Esta expresión indica que las transacciones que contienen todos los ítems de \(X\) también pueden incluir los de \(Y\), con una frecuencia condicional medida mediante la confianza. Así, esta técnica permite explorar asociaciones entre características cualitativas. Estas relaciones describen coocurrencia y no implican causalidad.

2 LIBRERIAS

library(readxl)
library(arules)
## Cargando paquete requerido: Matrix
## 
## Adjuntando el paquete: 'arules'
## The following objects are masked from 'package:base':
## 
##     abbreviate, write
library(ggplot2)
library(dplyr)
## 
## Adjuntando el paquete: 'dplyr'
## The following objects are masked from 'package:arules':
## 
##     intersect, recode, setdiff, setequal, union
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(igraph)
## 
## Adjuntando el paquete: 'igraph'
## The following objects are masked from 'package:dplyr':
## 
##     as_data_frame, groups, union
## The following object is masked from 'package:arules':
## 
##     union
## The following objects are masked from 'package:stats':
## 
##     decompose, spectrum
## The following object is masked from 'package:base':
## 
##     union
library(scales)

3 DATOS SIMULADOS

set.seed(123)
library(readxl)
datos <- read_excel("C:/Users/PC/Downloads/proyectos de mineria de datos/reglas de asociacion/transacciones_any.xlsx")
datos
## # A tibble: 600 × 15
##    Transaccion Arroz Azucar Aceite Fideos Leche Huevos   Pan Pollo  Papa Cebolla
##          <dbl> <dbl>  <dbl>  <dbl>  <dbl> <dbl>  <dbl> <dbl> <dbl> <dbl>   <dbl>
##  1           1     0      1      1      1     1      0     0     1     0       0
##  2           2     1      0      1      1     1      0     0     1     1       0
##  3           3     1      0      1      1     0      1     0     1     1       1
##  4           4     1      0      1      0     0      1     0     0     0       0
##  5           5     0      0      0      0     0      0     1     0     0       0
##  6           6     1      0      1      0     0      1     0     0     0       0
##  7           7     0      1      1      0     0      0     1     0     0       0
##  8           8     1      1      1      1     1      0     0     0     1       0
##  9           9     1      1      0      0     1      1     0     0     1       0
## 10          10     1      0      0      0     1      1     1     0     0       1
## # ℹ 590 more rows
## # ℹ 4 more variables: Tomate <dbl>, Avena <dbl>, Sal <dbl>, Lentejas <dbl>
# Excluir el identificador: no representa un producto.
datos_productos <- as.data.frame(datos[, names(datos) != "Transaccion"])
n <- nrow(datos_productos)

# Comprobar la codificacion antes de crear las canastas.
if (n == 0 || ncol(datos_productos) == 0) {
  stop("El Excel no contiene transacciones o productos.")
}
if (anyNA(datos_productos) ||
    !all(as.matrix(datos_productos) %in% c(0, 1))) {
  stop("Los productos deben contener solo 0 y 1, sin valores perdidos.")
}

# Mantener el formato de lista .
transacciones <- vector("list", n)
for (i in seq_len(n)) {
  compra <- names(datos_productos)[
    as.numeric(unlist(datos_productos[i, ], use.names = FALSE)) == 1
  ]
  transacciones[[i]] <- unique(compra)
}

canastas <- as(transacciones, "transactions")
cat("\nRESUMEN DE LAS TRANSACCIONES\n")
## 
## RESUMEN DE LAS TRANSACCIONES
print(summary(canastas))
## transactions as itemMatrix in sparse format with
##  600 rows (elements/itemsets/transactions) and
##  14 columns (items) and a density of 0.4083333 
## 
## most frequent items:
##  Aceite   Arroz    Papa     Pan  Azucar (Other) 
##     467     394     313     254     240    1762 
## 
## element (itemset/transaction) length distribution:
## sizes
##   0   1   2   3   4   5   6   7   8   9  10  11  12 
##   1   6  24  59  83 106 114  88  56  47  12   2   2 
## 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.000   4.000   6.000   5.717   7.000  12.000 
## 
## includes extended item information - examples:
##   labels
## 1 Aceite
## 2  Arroz
## 3  Avena
cat("\nNumero total de compras:", length(canastas), "\n")
## 
## Numero total de compras: 600
# Matriz binaria: filas = compras; columnas = productos
matriz <- as(canastas, "matrix") * 1
matriz <- as.data.frame(matriz)

Interpretación: El resumen muestra 600 transacciones simuladas y 14 productos. Los estadísticos nos indican que existe una transacción sin productos. El 25 % de las compras contiene como máximo cuatro productos. La mitad de las compras contiene como máximo seis productos. Cada compra contiene, en promedio, aproximadamente 5,72 productos distintos. El 75 % de las compras contiene como máximo siete productos. La canasta más grande contiene doce productos distintos.

El tamaño más frecuente es seis productos, observado en 114 compras (19 %). También existe una compra vacía, cuyo significado debe revisarse antes de decidir si corresponde conservarla.

4 FRECUENCIA Y SOPORTE

frecuencias <- colSums(matriz)
soportes <- frecuencias / nrow(matriz)

tabla_productos <- data.frame(
  Producto = names(frecuencias),
  Frecuencia = as.numeric(frecuencias),
  Soporte = as.numeric(soportes)
) |>
  arrange(desc(Soporte))

cat("\nFRECUENCIA Y SOPORTE DE CADA PRODUCTO\n")
## 
## FRECUENCIA Y SOPORTE DE CADA PRODUCTO
print(tabla_productos, row.names = FALSE)
##  Producto Frecuencia   Soporte
##    Aceite        467 0.7783333
##     Arroz        394 0.6566667
##      Papa        313 0.5216667
##       Pan        254 0.4233333
##    Azucar        240 0.4000000
##    Fideos        240 0.4000000
##    Tomate        227 0.3783333
##     Avena        224 0.3733333
##    Huevos        214 0.3566667
##     Leche        209 0.3483333
##     Pollo        188 0.3133333
##   Cebolla        176 0.2933333
##       Sal        159 0.2650000
##  Lentejas        125 0.2083333
g_frecuencia <- ggplot(tabla_productos,
                       aes(x = reorder(Producto, Frecuencia),
                           y = Frecuencia)) +
  geom_col(fill = "steelblue") +
  coord_flip() +
  labs(title = "Frecuencia de compra por producto",
       subtitle = "Cantidad de transacciones que contienen cada producto",
       x = "Producto", y = "Numero de transacciones") +
  theme_minimal(base_size = 12)
print(g_frecuencia)

g_soporte_producto <- ggplot(tabla_productos,
                             aes(x = reorder(Producto, Soporte),
                                 y = Soporte)) +
  geom_col(fill = "darkseagreen4") +
  coord_flip() +
  scale_y_continuous(labels = percent_format(accuracy = 1)) +
  labs(title = "Soporte individual de los productos",
       x = "Producto", y = "Soporte") +
  theme_minimal(base_size = 12)
print(g_soporte_producto)

Interpretación: - Aceite tiene la mayor presencia: aparece en 467 compras, equivalentes al 77,83 %. Es decir, aproximadamente 78 de cada 100 transacciones contienen Aceite. - Arroz y Papa ocupan el segundo y tercer lugar, con soportes de 65,67 % y 52,17 %. Junto con Aceite, son los únicos productos presentes en más de la mitad de las compras. - Azúcar y Fideos tienen igual frecuencia: aparecen en 240 compras cada uno. Esto no significa que estén presentes en las mismas transacciones. - Lentejas tiene la menor presencia, con 125 compras y soporte de 20,83 %. Esto no permite concluir que sea poco rentable ni que tenga baja demanda en hogares reales.

Estos resultados describen la presencia individual de los productos y constituyen la referencia para interpretar posteriormente las reglas de asociación mediante soporte, confianza y lift.

5 ALGORITMO APRIORI

# Ajustar soporte y confianza segun el tamano y objetivo del estudio.
reglas <- apriori(
  canastas,
  parameter = list(
    supp = 0.05,
    conf = 0.50,
    minlen = 2,
    maxlen = 3,
    target = "rules"
  )
)
## Apriori
## 
## Parameter specification:
##  confidence minval smax arem  aval originalSupport maxtime support minlen
##         0.5    0.1    1 none FALSE            TRUE       5    0.05      2
##  maxlen target  ext
##       3  rules TRUE
## 
## Algorithmic control:
##  filter tree heap memopt load sort verbose
##     0.1 TRUE TRUE  FALSE TRUE    2    TRUE
## 
## Absolute minimum support count: 30 
## 
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[14 item(s), 600 transaction(s)] done [0.00s].
## sorting and recoding items ... [14 item(s)] done [0.00s].
## creating transaction tree ... done [0.00s].
## checking subsets of size 1 2 3
## Warning in apriori(canastas, parameter = list(supp = 0.05, conf = 0.5, minlen =
## 2, : Mining stopped (maxlen reached). Only patterns up to a length of 3
## returned!
##  done [0.00s].
## writing ... [310 rule(s)] done [0.00s].
## creating S4 object  ... done [0.00s].
cat("\nCantidad de reglas encontradas:", length(reglas), "\n")
## 
## Cantidad de reglas encontradas: 310
if (length(reglas) == 0) {
  stop("No se encontraron reglas. Pruebe supp = 0.02 y/o conf = 0.20.")
}

Interpretación: Se aplicó el algoritmo Apriori a 600 transacciones simuladas, utilizando un soporte mínimo de 0,05, equivalente a 30 compras, una confianza mínima de 0,50 y una longitud total de dos a tres productos. Se obtuvieron 310 reglas que satisfacen estos criterios.

6 4. TABLA DE REGLAS Y MEDIDAS

q <- quality(reglas)

tabla_reglas <- data.frame(
  Regla = labels(reglas),
  Soporte = q$support,
  Confianza = q$confidence,
  Lift = q$lift,
  stringsAsFactors = FALSE
) |>
  arrange(desc(Lift))

cat("\nPRIMERAS 20 REGLAS ORDENADAS POR LIFT\n")
## 
## PRIMERAS 20 REGLAS ORDENADAS POR LIFT
print(head(tabla_reglas, 20), row.names = FALSE)
##                           Regla    Soporte Confianza     Lift
##      {Cebolla,Leche} => {Avena} 0.09500000 0.8260870 2.212733
##       {Azucar,Leche} => {Avena} 0.12333333 0.8131868 2.178179
##         {Avena,Papa} => {Leche} 0.15000000 0.7500000 2.153110
##       {Avena,Azucar} => {Leche} 0.12333333 0.7400000 2.124402
##         {Leche,Papa} => {Avena} 0.15000000 0.7758621 2.078202
##       {Leche,Tomate} => {Avena} 0.10833333 0.7738095 2.072704
##       {Avena,Fideos} => {Leche} 0.10666667 0.7191011 2.064405
##  {Cebolla,Lentejas} => {Tomate} 0.05333333 0.7804878 2.062963
##       {Aceite,Leche} => {Avena} 0.19666667 0.7564103 2.026099
##        {Arroz,Leche} => {Avena} 0.16000000 0.7559055 2.024747
##          {Leche,Pan} => {Avena} 0.11333333 0.7555556 2.023810
##      {Avena,Cebolla} => {Leche} 0.09500000 0.7037037 2.020202
##       {Avena,Tomate} => {Leche} 0.10833333 0.6989247 2.006482
##              {Leche} => {Avena} 0.26000000 0.7464115 1.999316
##              {Avena} => {Leche} 0.26000000 0.6964286 1.999316
##        {Leche,Pollo} => {Avena} 0.09000000 0.7397260 1.981409
##     {Avena,Tomate} => {Cebolla} 0.09000000 0.5806452 1.979472
##          {Leche,Sal} => {Avena} 0.07000000 0.7368421 1.973684
##       {Fideos,Leche} => {Avena} 0.10666667 0.7356322 1.970443
##       {Aceite,Avena} => {Leche} 0.19666667 0.6860465 1.969512

Interpretación: Las 20 reglas muestran asociación positiva porque todas tienen lift mayor que 1. La regla {Cebolla, Leche} ⇒ {Avena} registra el mayor lift de significancia, con soporte de 9,50 % de todas las compras aparecen los tres productos juntos y confianza de 82,61 % también incluyen Avena, sustentada en 57 transacciones. No obstante, la relación Leche–Avena presenta mayor cobertura: ambos productos aparecen conjuntamente en 156 compras, equivalentes al 26 % del total, y las reglas en ambas direcciones alcanzan un lift aproximado de 1,999. La reiteración de esta combinación en distintos antecedentes evidencia que varias reglas describen patrones relacionados.

7 CALCULO MANUAL DE SOPORTE, CONFIANZA Y LIFT

# Ejemplo de regla: Arroz -> Aceite.
# Cambie los nombres por productos que existan en la base.

A <- "Arroz"
B <- "Aceite"

if (!(A %in% names(matriz)) || !(B %in% names(matriz))) {
  stop("Los productos elegidos no existen en la matriz.")
}

n_total <- nrow(matriz)
n_A <- sum(matriz[[A]] == 1)
n_B <- sum(matriz[[B]] == 1)
n_AB <- sum(matriz[[A]] == 1 & matriz[[B]] == 1)

support_A <- n_A / n_total
support_B <- n_B / n_total
support_AB <- n_AB / n_total

confidence_A_B <- ifelse(n_A > 0, n_AB / n_A, NA_real_)
lift_A_B <- ifelse(support_B > 0,
                   confidence_A_B / support_B, NA_real_)

tabla_calculo_manual <- data.frame(
  Indicador = c(
    "Total de transacciones",
    paste("Compras con", A),
    paste("Compras con", B),
    paste("Compras con", A, "y", B),
    paste("Soporte de", A),
    paste("Soporte de", B),
    paste("Soporte conjunto", A, "y", B),
    paste("Confianza", A, "->", B),
    paste("Lift", A, "->", B)
  ),
  Valor = c(
    n_total, n_A, n_B, n_AB,
    support_A, support_B, support_AB,
    confidence_A_B, lift_A_B
  )
)

cat("\nCALCULO MANUAL DE LA REGLA ", A, " -> ", B, "\n", sep = "")
## 
## CALCULO MANUAL DE LA REGLA Arroz -> Aceite
print(tabla_calculo_manual, row.names = FALSE)
##                        Indicador       Valor
##           Total de transacciones 600.0000000
##                Compras con Arroz 394.0000000
##               Compras con Aceite 467.0000000
##       Compras con Arroz y Aceite 346.0000000
##                 Soporte de Arroz   0.6566667
##                Soporte de Aceite   0.7783333
##  Soporte conjunto Arroz y Aceite   0.5766667
##        Confianza Arroz -> Aceite   0.8781726
##             Lift Arroz -> Aceite   1.1282731
cat("\nFORMULAS APLICADAS\n")
## 
## FORMULAS APLICADAS
cat("Soporte conjunto = n(A y B) / N = ",
    n_AB, "/", n_total, " = ", round(support_AB, 4), "\n", sep = "")
## Soporte conjunto = n(A y B) / N = 346/600 = 0.5767
cat("Confianza = n(A y B) / n(A) = ",
    n_AB, "/", n_A, " = ", round(confidence_A_B, 4), "\n", sep = "")
## Confianza = n(A y B) / n(A) = 346/394 = 0.8782
cat("Lift = confianza / soporte(B) = ",
    round(confidence_A_B, 4), "/", round(support_B, 4),
    " = ", round(lift_A_B, 4), "\n", sep = "")
## Lift = confianza / soporte(B) = 0.8782/0.7783 = 1.1283
cat("\nINTERPRETACION AUTOMATICA DEL LIFT\n")
## 
## INTERPRETACION AUTOMATICA DEL LIFT
if (lift_A_B > 1) {
  cat("Lift > 1: asociacion positiva en estas transacciones.\n")
} else if (abs(lift_A_B - 1) < 1e-8) {
  cat("Lift = 1: frecuencia compatible con independencia.\n")
} else {
  cat("Lift < 1: asociacion negativa en estas transacciones.\n")
}
## Lift > 1: asociacion positiva en estas transacciones.

Interpretación: La regla {Arroz} ⇒ {Aceite} presenta asociación positiva: ambos productos aparecen juntos con mayor frecuencia que la esperada bajo independencia. El soporte es de 57,67 % de todas las compras aparecen Arroz y Aceite juntos. Entre las compras que contienen Arroz, la confianza es de 87,82 % también incluye Aceite. Esto significa que la presencia de Aceite entre las compras con Arroz es 1,128 veces su presencia general, aproximadamente 12,83 % mayor en términos relativos. El lift de 1,1283 evidencia una asociación positiva.

8 FIGURAS INDIVIDUALES PARA SOPORTE, CONFIANZA Y LIFT

# Cada figura muestra las 15 reglas con mayor valor del indicador.

top_soporte <- tabla_reglas |>
  arrange(desc(Soporte)) |>
  slice_head(n = 15)

g_soporte <- ggplot(top_soporte,
                    aes(x = reorder(Regla, Soporte), y = Soporte)) +
  geom_col(fill = "dodgerblue3") +
  coord_flip() +
  scale_y_continuous(labels = percent_format(accuracy = 1)) +
  labs(title = "15 reglas con mayor soporte",
       x = "Regla", y = "Soporte") +
  theme_minimal(base_size = 11)
print(g_soporte)

Interpretación: Las reglas {Arroz} ⇒ {Aceite} y {Aceite} ⇒ {Arroz} presentan el mayor soporte: 57,67 %, correspondiente a 346 de las 600 compras. Estas reglas describen combinaciones que abarcan una proporción elevada de las compras. Sin embargo, mayor soporte no implica mayor fuerza de asociación: dos productos frecuentes pueden aparecer juntos muchas veces simplemente por su elevada presencia individual.

top_confianza <- tabla_reglas |>
  arrange(desc(Confianza)) |>
  slice_head(n = 15)

g_confianza <- ggplot(top_confianza,
                      aes(x = reorder(Regla, Confianza),
                          y = Confianza)) +
  geom_col(fill = "darkorange2") +
  coord_flip() +
  scale_y_continuous(labels = percent_format(accuracy = 1),
                     limits = c(0, 1)) +
  labs(title = "15 reglas con mayor confianza",
       x = "Regla", y = "Confianza") +
  theme_minimal(base_size = 11)
print(g_confianza)

Interpretación: La primera regla es {Cebolla, Fideos} ⇒ {Aceite}, con confianza cercana al 96 %. Esto significa que, entre las compras que contienen Cebolla y Fideos simultáneamente, aproximadamente el 96 % también incluye Aceite.

top_lift <- tabla_reglas |>
  arrange(desc(Lift)) |>
  slice_head(n = 15)

g_lift <- ggplot(top_lift,
                 aes(x = reorder(Regla, Lift), y = Lift)) +
  geom_col(fill = "mediumpurple4") +
  geom_hline(yintercept = 1, linetype = "dashed",
             linewidth = 0.8) +
  coord_flip() +
  labs(title = "15 reglas con mayor lift",
       subtitle = "La linea discontinua representa lift = 1",
       x = "Regla", y = "Lift") +
  theme_minimal(base_size = 11)
print(g_lift)

Interpretación: La regla {Cebolla, Leche} ⇒ {Avena} ocupa el primer lugar, con lift de 2,213. Entre las compras que contienen Cebolla y Leche, la presencia de Avena es 2,213 veces su frecuencia general. Leche y Avena presentan una asociación positiva y aparecen juntas en una proporción considerable de las compras. Las reglas que añaden otros productos deben compararse con esta relación simple para determinar qué información adicional aportan.

Interpretación: Los gráficos muestran que las reglas de mayor cobertura involucran principalmente a Aceite, Arroz y Papa, mientras que las mayores confianzas corresponden a reglas cuyo consecuente es Aceite. No obstante, su elevada frecuencia individual exige interpretar estas confianzas junto con el lift. Las mayores asociaciones relativas se concentran en combinaciones relacionadas con Leche y Avena. Por ello, la selección de reglas debe considerar conjuntamente cobertura, confianza, lift y simplicidad. Estos resultados describen las transacciones simuladas y no demuestran causalidad ni efectos comerciales.

9 GRAFICO DE DISPERSION: SOPORTE VS CONFIANZA

# Tamano y color del circulo representan el lift.

g_dispersion <- ggplot(tabla_reglas,
                       aes(x = Soporte, y = Confianza,
                           size = Lift, color = Lift)) +
  geom_point(alpha = 0.75) +
  scale_x_continuous(labels = percent_format(accuracy = 1)) +
  scale_y_continuous(labels = percent_format(accuracy = 1),
                     limits = c(0, 1)) +
  labs(title = "Mapa de reglas: soporte, confianza y lift",
       subtitle = "Cada circulo representa una regla",
       x = "Soporte", y = "Confianza",
       size = "Lift", color = "Lift") +
  theme_minimal(base_size = 12)
print(g_dispersion)

Interpretación: El mapa muestra una concentración de reglas con soportes aproximados de 5 % a 20 % y confianzas principalmente entre 50 % y 80 %. Las reglas de mayor cobertura no coinciden necesariamente con las de mayor lift, mientras que varias asociaciones de mayor intensidad relativa presentan menor soporte. En consecuencia, la selección debe equilibrar cobertura y fuerza de asociación, considerando conjuntamente soporte, confianza y lift. El gráfico describe las reglas obtenidas de las transacciones simuladas y no permite establecer causalidad ni utilidad comercial por sí solo.

10 8. GRAFO DE ASOCIACION: CIRCULOS, LINEAS Y FLECHAS

# Para que el grafo sea legible se usan reglas simples A -> B,
# donde antecedente y consecuente contienen un solo producto.

reglas_simples <- subset(
  reglas,
  size(lhs(reglas)) == 1 & size(rhs(reglas)) == 1
)

if (length(reglas_simples) > 0) {
  
  qs <- quality(reglas_simples)
  lhs_text <- labels(lhs(reglas_simples))
  rhs_text <- labels(rhs(reglas_simples))
  
  aristas <- data.frame(
    Desde = gsub("[{}]", "", lhs_text),
    Hacia = gsub("[{}]", "", rhs_text),
    Soporte = qs$support,
    Confianza = qs$confidence,
    Lift = qs$lift,
    stringsAsFactors = FALSE
  )
  
  # Evitar que el grafo se vuelva demasiado denso:
  # seleccionar las 25 reglas de mayor lift.
  aristas <- aristas |>
    arrange(desc(Lift)) |>
    slice_head(n = 25)
  
  nodos <- unique(c(aristas$Desde, aristas$Hacia))
  tamanos <- tabla_productos$Frecuencia[
    match(nodos, tabla_productos$Producto)
  ]
  
  grafo <- graph_from_data_frame(
    aristas,
    directed = TRUE,
    vertices = data.frame(
      name = nodos,
      frecuencia = tamanos
    )
  )
  
  # Grosor de linea proporcional a confianza.
  E(grafo)$width <- 1 + 5 * E(grafo)$Confianza
  
  # Etiqueta de cada flecha: lift redondeado.
  E(grafo)$label <- paste0("L=", round(E(grafo)$Lift, 2))
  
  # Tamano del circulo proporcional a frecuencia.
  V(grafo)$size <- 12 + 8 *
    V(grafo)$frecuencia / max(V(grafo)$frecuencia, na.rm = TRUE)
  
  # Color de nodos y flechas para distinguir elementos.
  V(grafo)$color <- "lightblue"
  V(grafo)$frame.color <- "steelblue4"
  V(grafo)$label.color <- "black"
  V(grafo)$label.cex <- 0.8
  E(grafo)$color <- "gray55"
  E(grafo)$arrow.size <- 0.5
  E(grafo)$label.cex <- 0.7
  E(grafo)$curved <- 0.15
  
  set.seed(123)
  plot(
    grafo,
    layout = layout_with_fr(grafo),
    main = "Red dirigida de reglas de asociacion",
    vertex.label = V(grafo)$name,
    vertex.label.dist = 0,
    edge.label = E(grafo)$label,
    margin = 0.15
  )
  
  cat("\nLECTURA DEL GRAFO:\n")
  cat("- Cada circulo representa un producto.\n")
  cat("- El tamano del circulo representa la frecuencia del producto.\n")
  cat("- La flecha indica la direccion de la regla A -> B.\n")
  cat("- El grosor de la flecha representa la confianza.\n")
  cat("- La etiqueta L indica el lift de la regla.\n")
  
} else {
  cat("No hay reglas simples A -> B para construir el grafo.\n")
  cat("Pruebe reducir el soporte minimo o la confianza minima.\n")
}

## 
## LECTURA DEL GRAFO:
## - Cada circulo representa un producto.
## - El tamano del circulo representa la frecuencia del producto.
## - La flecha indica la direccion de la regla A -> B.
## - El grosor de la flecha representa la confianza.
## - La etiqueta L indica el lift de la regla.

Interpretación: La red permite visualizar las reglas simples seleccionadas. Aceite presenta el mayor tamaño de nodo debido a su elevada frecuencia, mientras que las relaciones Leche–Avena y Cebolla–Tomate destacan por sus lifts aproximados de 2,00 y 1,80, respectivamente. Estos resultados evidencian que la frecuencia de un producto y la fuerza relativa de sus asociaciones son características diferentes. El grosor de las conexiones representa confianza y debe interpretarse junto con el lift. La red describe asociaciones en las transacciones simuladas, sin establecer causalidad ni grupos estadísticos de productos.