Skip to Content
Course content

105: Market Basket Analysis with arules

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you're managing a local coffee shop. You’ve noticed a pattern: almost every time someone orders a blueberry muffin, they also grab a medium roast coffee. You don't have a spreadsheet proving it yet, but your gut tells you that if you move the muffins right next to the coffee brewing station, you'll sell more of both. You're essentially performing a mental "Market Basket Analysis."

In R, we stop guessing and start quantifying this. We map that coffee shop intuition onto three specific metrics: Support (how often the muffin-coffee combo appears across all receipts), Confidence (of the people who bought muffins, what percentage also bought coffee?), and Lift (does buying a muffin actually *increase* the likelihood of buying coffee, or do people just buy coffee regardless of the muffin?).

Turning Receipts into Transactions

The biggest hurdle when starting with the arules package is that it doesn't use standard data frames. If you try to pass a regular tibble into the Apriori algorithm, it'll throw an error. We need a transactions object.

I've found that the easiest way to handle this is to ensure your data is in a "long" format (one row per item per transaction) and then convert it. Here is how we set up a small dataset of grocery trips:

library(arules)

# Imagine this is our raw sales data
sales_data <- data.frame(
  order_id = c(1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5),
  item = c("Milk", "Bread", "Eggs", "Milk", "Bread", "Milk", "Diapers", "Bread", "Eggs", "Milk", "Bread", "Diapers")
)

# Convert to a transactions object
# We split the items by order_id
trans <- as(split(sales_data$item, sales_data$order_id), "transactions")
inspect(trans)

Mining Rules with the Apriori Algorithm

Now that our data is in the right format, we use the apriori() function. This is where the heavy lifting happens. The algorithm looks for combinations of items that appear together more often than would be expected by random chance.

You can't just run it blindly, though. If you do, you'll likely end up with thousands of rules that are technically true but practically useless (like "People who buy bread also buy milk"). I usually suggest setting a minimum support threshold to filter out the rare combinations and a confidence threshold to ensure the rule is reliable.

# Find rules where the items appear in at least 20% of transactions
# and the rule is true at least 60% of the time
rules <- apriori(trans, 
                 parameter = list(supp = 0.2, conf = 0.6))

# Let's see the top rules sorted by 'lift'
# Lift > 1 means the items are positively associated
sorted_rules <- sort(rules, by = "lift", decreasing = TRUE)
inspect(sorted_rules[1:5])

Sifting Through the Noise

When you look at the output, you'll see something like {Bread} => {Milk}. This is your "If-Then" statement. But here is the pro tip: don't rely on confidence alone. Confidence can be misleading if the "Then" item is extremely popular. If 90% of all your customers buy milk regardless of anything else, a confidence of 90% for {Bread} => {Milk} tells you absolutely nothing about the relationship between bread and milk.

That's why we look at Lift. Lift is the ratio of the observed support to that expected support if the items were independent. If the lift is 1, there's no relationship. If it's 3, the customer is three times more likely to buy milk because they bought bread. That's the insight you actually take to your manager.




📋 Practical Task

Analyzing a Vintage Record Store's Sales Patterns

You've been handed a dataset from a vintage record store. They want to know which genres of vinyl are frequently bought together so they can reorganize their shelving. Use the arules package to find the associations.

The Data:

record_sales <- data.frame(
  txn_id = c(1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7),
  genre = c("Jazz", "Blues", "Rock", "Metal", "Rock", "Jazz", "Blues", "Rock", "Metal", "Rock", "Metal", "Jazz", "Blues", "Funk", "Rock", "Metal")
)

Your Goal:

  1. Convert the record_sales data frame into a transactions object.
  2. Run the apriori() algorithm with a minimum support of 0.2 and a minimum confidence of 0.5.
  3. Sort the resulting rules by lift in descending order.
  4. Identify the rule with the highest lift and print it using inspect().
Rating
0 0

There are no comments for now.

to be the first to leave a comment.