Which products are bought together?
Market basket analysis finds the items that customers buy together. It is the simplest form of data mining, the search for patterns in records.
A shop can use a pattern to put two products on one shelf, to bundle them, or to stock enough of both. You will learn to count the patterns and to tell which ones are common.
By the end of this lesson
Note
I can find the items that often occur together in a set of baskets.
Key words
| Word | What it means | Example |
|---|---|---|
| Basket | the items bought in one visit | bread, milk |
| Itemset | one or more items taken together | |
| Support | the share of baskets that hold an itemset | |
| Minimum support | the lowest support that counts as common | |
| Frequent itemset | an itemset whose support reaches the minimum |
The cells students fill in are left blank in this preview.
Support is a share of baskets
A basket is the list of items one customer bought in one visit. An itemset is any group of items, such as bread, or bread and milk.
Support is the number of baskets that hold every item in the itemset, divided by the number of baskets. A support of 0.5 means half the baskets hold it.
Worked example: eight baskets from a corner shop
| Basket | Items | Holds bread? | Holds bread and milk? |
|---|---|---|---|
| 1 | bread, milk, eggs | Yes | Yes |
| 2 | bread, butter | Yes | No |
| 3 | milk, eggs, tea | No | No |
| 4 | bread, milk, butter | Yes | Yes |
| 5 | bread, milk, eggs, butter | Yes | Yes |
| 6 | milk, tea | No | No |
| 7 | bread, eggs | Yes | No |
| 8 | bread, milk, butter | Yes | Yes |
The cells students fill in are left blank in this preview.
Count the support of an itemset
baskets = [
["bread", "milk", "eggs"],
["bread", "butter"],
["milk", "eggs", "tea"],
["bread", "milk", "butter"],
["bread", "milk", "eggs", "butter"],
["milk", "tea"],
["bread", "eggs"],
["bread", "milk", "butter"],
]
def support(items):
count = 0
for basket in baskets:
found = True
for item in items:
if item not in basket:
found = False
if found:
count = count + 1
return count / len(baskets)
print(support(["bread"]))
print(support(["bread", "milk"]))
# Change the second list to ["milk", "eggs"]. Work out the answer by hand first.
A minimum support keeps only the common patterns
A shop with ten thousand products has far too many pairs to read. So we choose a minimum support and keep only the itemsets that reach it. These are the frequent itemsets.
Here the minimum is 3 baskets out of 8, which is a support of 0.375. Pairs below it are dropped as too rare to act on.
Worked example: every pair that appears
| Pair | Baskets | Support | Frequent at 3 baskets? |
|---|---|---|---|
| bread + butter | 4 | 0.5 | Yes |
| bread + eggs | 3 | 0.375 | Yes |
| bread + milk | 4 | 0.5 | Yes |
| butter + eggs | 1 | 0.125 | No |
| butter + milk | 3 | 0.375 | Yes |
| eggs + milk | 3 | 0.375 | Yes |
| eggs + tea | 1 | 0.125 | No |
| milk + tea | 2 | 0.25 | No |
The cells students fill in are left blank in this preview.
Count one pair with Python
docker exec jupyter python3 -c "print(sum('bread' in b and 'milk' in b for b in ['bread milk eggs', 'bread butter', 'milk eggs tea', 'bread milk butter', 'bread milk eggs butter', 'milk tea', 'bread eggs', 'bread milk butter']))"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A common mistake
Warning
Many people think a frequent pair is a real link between two items. Two very popular items will often share a basket by chance. Support only says how often a pair occurs. The next lesson adds a measure that tests whether the items really go together.
Rare items can be dropped first
If tea is in only 2 baskets, any pair with tea is in at most 2 baskets. So when tea is below the minimum, you can skip every pair that holds it.
This is the idea behind the Apriori method: count single items first, drop the rare ones, then build pairs only from the survivors. It saves a lot of counting on large shops.
Treat each bike hire day as a basket
docker exec jupyter python3 -c "import csv; days = list(csv.DictReader(open('hires.csv'))); print(sum(d['weekday'] in ('Sat', 'Sun') and int(d['hires']) >= 300 for d in days), 'of', len(days))"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Any row of facts can become a basket
The lab keeps one row for each day of 2025. If you call a day a weekend, busy (300 hires or more) or rainy, each day becomes a basket of those facts.
The command counted the days that hold both "weekend" and "busy". It printed 57 of 365, so the support of that pair is 57 / 365, which is about 0.156.
Going further
In the code block, raise the minimum from 3 baskets to 4. Which pairs remain? Then try to count triples such as bread, milk and butter.
Explain why the number of possible itemsets grows so fast, and why dropping rare items first saves work.