Apriori Algorithm is a foundational method in data mining used for discovering frequent itemsets and generating association rules. Its significance lies in its ability to identify relationships between items in large datasets which is particularly valuable in market basket analysis. https://www.geeksforgeeks.org/apriori-algorithm/ For example, if a grocery store finds that customers who buy bread often also buy butter, it can use this information to optimize product placement or marketing strategies.
The Groceries data set contains 1 month (30 days) of real-world point-of-sale transaction data from a typical local grocery outlet. The data set contains 9835 transactions and the items are aggregated to 169 categories.
Reference: Michael Hahsler, Kurt Hornik, and Thomas Reutterer (2006) Implications of probabilistic data modeling for mining association rules. In M. Spiliopoulou, R. Kruse, C. Borgelt, A. Nuernberger, and W. Gaul, editors, From Data and Information Analysis to Knowledge Engineering, Studies in Classification, Data Analysis, and Knowledge Organization, pages 598–605. Springer-Verlag.
library(arules)
library(arulesViz)
library(networkD3)
library(dplyr)
library(tidyr)
library(plotly)
library(igraph)
library(ggraph)
library(tidyverse)
data("Groceries")
summary(Groceries)
## transactions as itemMatrix in sparse format with
## 9835 rows (elements/itemsets/transactions) and
## 169 columns (items) and a density of 0.02609146
##
## most frequent items:
## whole milk other vegetables rolls/buns soda
## 2513 1903 1809 1715
## yogurt (Other)
## 1372 34055
##
## element (itemset/transaction) length distribution:
## sizes
## 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
## 2159 1643 1299 1005 855 645 545 438 350 246 182 117 78 77 55 46
## 17 18 19 20 21 22 23 24 26 27 28 29 32
## 29 14 14 9 11 4 6 1 1 1 1 3 1
##
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.000 2.000 3.000 4.409 6.000 32.000
##
## includes extended item information - examples:
## labels level2 level1
## 1 frankfurter sausage meat and sausage
## 2 sausage sausage meat and sausage
## 3 liver loaf sausage meat and sausage
itemFreqPlot <- itemFrequencyPlot(Groceries, topN = 10, type = "relative", main = "Top 10 Groceries")
rules <- apriori(Groceries, parameter = list(supp = 0.01, conf = 0.5, minlen = 2))
## Apriori
##
## Parameter specification:
## confidence minval smax arem aval originalSupport maxtime support minlen
## 0.5 0.1 1 none FALSE TRUE 5 0.01 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: 98
##
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[169 item(s), 9835 transaction(s)] done [0.00s].
## sorting and recoding items ... [88 item(s)] done [0.00s].
## creating transaction tree ... done [0.00s].
## checking subsets of size 1 2 3 4 done [0.00s].
## writing ... [15 rule(s)] done [0.00s].
## creating S4 object ... done [0.00s].
rules.sorted <- sort(rules, by = "lift", decreasing = TRUE)
rules.clean <- rules.sorted[!is.redundant(rules.sorted)]
inspect(rules.clean[1:5])
## lhs rhs support
## [1] {citrus fruit, root vegetables} => {other vegetables} 0.01037112
## [2] {tropical fruit, root vegetables} => {other vegetables} 0.01230300
## [3] {root vegetables, rolls/buns} => {other vegetables} 0.01220132
## [4] {root vegetables, yogurt} => {other vegetables} 0.01291307
## [5] {curd, yogurt} => {whole milk} 0.01006609
## confidence coverage lift count
## [1] 0.5862069 0.01769192 3.029608 102
## [2] 0.5845411 0.02104728 3.020999 121
## [3] 0.5020921 0.02430097 2.594890 120
## [4] 0.5000000 0.02582613 2.584078 127
## [5] 0.5823529 0.01728521 2.279125 99
rules_df <- as(rules.clean, "data.frame")
rules_df$rule <- as.character(rules_df$rules)
rules_df <- separate(rules_df, rule, into = c("lhs", "rhs"), sep = "=>")
rules_df <- rules_df %>%
mutate(lhs = gsub("[{ }]", "", lhs), rhs = gsub("[{ }]", "", rhs))
head(rules_df)
## rules support confidence
## 7 {citrus fruit,root vegetables} => {other vegetables} 0.01037112 0.5862069
## 8 {tropical fruit,root vegetables} => {other vegetables} 0.01230300 0.5845411
## 13 {root vegetables,rolls/buns} => {other vegetables} 0.01220132 0.5020921
## 11 {root vegetables,yogurt} => {other vegetables} 0.01291307 0.5000000
## 1 {curd,yogurt} => {whole milk} 0.01006609 0.5823529
## 2 {other vegetables,butter} => {whole milk} 0.01148958 0.5736041
## coverage lift count lhs rhs
## 7 0.01769192 3.029608 102 citrusfruit,rootvegetables othervegetables
## 8 0.02104728 3.020999 121 tropicalfruit,rootvegetables othervegetables
## 13 0.02430097 2.594890 120 rootvegetables,rolls/buns othervegetables
## 11 0.02582613 2.584078 127 rootvegetables,yogurt othervegetables
## 1 0.01728521 2.279125 99 curd,yogurt wholemilk
## 2 0.02003050 2.244885 113 othervegetables,butter wholemilk
nodes <- data.frame(name = unique(c(rules_df$lhs, rules_df$rhs)), id = 0:(length(unique(c(rules_df$lhs, rules_df$rhs))) - 1))
links <- merge(nodes, rules_df, by.x = "name", by.y = "lhs")
links <- links %>% rename(source = id)
links <- merge(nodes, links, by.x = "name", by.y = "rhs")
links <- links %>% rename(target = id, value = lift)
links <- links[, c("source", "target", "value")]
nodes$group <- 1
forceNetwork(Links = links, Nodes = nodes,
Source = "source", Target = "target",
Value = "value", NodeID = "name",
Group = "group",
opacity = 0.9, zoom = TRUE)
labels <- unique(c(rules_df$lhs, rules_df$rhs))
source_indices <- as.integer(factor(rules_df$lhs, levels = labels)) - 1
target_indices <- as.integer(factor(rules_df$rhs, levels = labels)) - 1
sankey_plot <- plot_ly(
type = "sankey",
node = list(
pad = 15,
thickness = 20,
line = list(color = "black", width = 0.5),
label = labels ),
link = list(
source = source_indices,
target = target_indices,
value = rules_df$lift)) %>%
layout(
title = "Sankey Diagram of Grocery Associations",
font = list(size = 10),
xaxis = list(showgrid = FALSE, zeroline = FALSE),
yaxis = list(showgrid = FALSE, zeroline = FALSE))
sankey_plot
rules.milk <- apriori(Groceries, parameter = list(supp = 0.01, conf = 0.5),
appearance = list(default = "lhs", rhs = "whole milk"),
control = list(verbose = FALSE))
rules.milk.sorted <- sort(rules.milk, by = "confidence", decreasing = TRUE)
rules_milk_df <- as(rules.milk.sorted, "data.frame")
rules_milk_df <- separate(rules_milk_df, rules, into = c("lhs", "rhs"), sep = "=>") %>%
mutate(lhs = gsub("[{ }]", "", lhs),
rhs = gsub("[{ }]", "", rhs))
edges <- rules_milk_df %>%
select(lhs, rhs, lift) %>%
rename(from = lhs, to = rhs, weight = lift)
g <- graph_from_data_frame(edges, directed = TRUE)
ggraph(g, layout = "kk") +
geom_edge_link(aes(edge_width = weight), alpha = 0.3, color = "yellow") +
geom_node_point(size = 5, color = "red") +
geom_node_text(aes(label = name), repel = TRUE, size = 5, check_overlap = TRUE) +
theme_void() +
ggtitle("Whole Milk")
The analysis of the Groceries dataset using the Apriori association rules revealed valuable insights into customer purchasing behavior. Whole milk, bread, butter, yogurt, and vegetables were identified as the most frequently purchased items, with strong associations between dairy products, bakery items, and vegetables.