Some things sell together. Ketchup ends up in the same basket as pasta; a phone case rides along with a new phone; users who read one article click a predictable next one. Frequent itemset mining is the family of data mining techniques that finds those combinations automatically, at scale, from raw transaction data. It is the engine behind "customers who bought this also bought…" and the classic market basket analysis that retailers use to lay out stores, bundle offers, and drive up basket size.
This guide explains the core ideas in plain English — support, confidence, and lift — walks through the two workhorse algorithms (Apriori and FP-Growth), and shows how the same job scales from a laptop to a cluster with MapReduce and Spark.
The problem: finding what goes together
Start with a pile of transactions (also called baskets), each a set of items:
T1: {bread, milk, eggs}
T2: {bread, butter}
T3: {milk, butter, eggs}
T4: {bread, milk, butter, eggs}
T5: {bread, milk, butter}
A frequent itemset is any group of items that appears together in "enough" baskets. The moment you know that {bread, milk} shows up often, you can act on it — recommend one when a shopper adds the other, place them near each other, or bundle them at a discount. Companies that put this into practice have reported meaningful lifts in revenue per order, because a well-timed recommendation nudges an existing buyer to add one more item.
The hard part is the sheer number of combinations. With N distinct items, the number of possible pairs alone is N × (N − 1) / 2, and that is before you consider triples, quadruples, and larger sets. A modest catalog of 10,000 products has nearly 50 million possible pairs. Checking every combination against every basket, and holding the counts in memory, is where a naive approach falls over. Every serious algorithm in this space is really a trick for avoiding counting combinations that cannot possibly be frequent.
Three numbers: support, confidence, lift
Association rule mining builds on frequent itemsets by turning them into "if-then" rules like {bread} → {milk}. Three metrics decide whether a rule is worth anything.
- Support — how common the itemset is overall.
support({bread, milk})is the fraction of all baskets that contain both. You set a minimum support threshold to define what counts as "frequent." - Confidence — how reliable the rule is.
confidence({bread} → {milk})is the share of bread-buyers who also buy milk. High confidence means the rule holds up. - Lift — how much better than chance the rule is. Lift above 1 means the two items are genuinely associated; lift of exactly 1 means they are independent (the rule is useless even if confidence looks high); lift below 1 means they actually repel each other.
Lift is the metric people forget and then get burned by. If almost everyone buys milk, a rule "bread → milk" will show high confidence purely because milk is everywhere — but its lift will be near 1, telling you the association is an illusion. Always read confidence and lift together.
The Apriori algorithm
Apriori is the foundational algorithm, and its insight is elegant: any subset of a frequent itemset must itself be frequent. Flip that around and you get the pruning rule that makes the whole thing tractable — if a single item is rare, no larger set containing it can be frequent, so you can throw it away immediately and never generate the combinations that include it.
Apriori works in passes, growing itemsets one item at a time:
- Pass 1 — count singles. Scan the data and count every individual item. Keep only those meeting the minimum support threshold; discard the rest.
- Pass 2 — count pairs. Form candidate pairs only from items that survived pass 1. Count them, keep the frequent ones.
- Pass k — grow. Build candidate itemsets of size
konly from frequent itemsets of sizek−1. Count, prune, repeat. - Stop when no new frequent itemsets are found.
Because each pass throws away the losers before generating the next round of candidates, the search space collapses fast. Sifting out even half of the below-threshold items early can cut memory use and computation by roughly a factor of four, since every discarded item also removes all the larger combinations it would have spawned.
The catch: Apriori scans the whole dataset once per pass, and generating candidate sets is expensive when data is dense. That weakness is exactly what the next algorithm fixes.
FP-Growth: faster on big, dense data
FP-Growth (Frequent Pattern Growth) avoids Apriori's candidate-generation bottleneck. It compresses the transactions into a compact in-memory structure called an FP-tree — a prefix tree where shared item sequences share branches — and then mines patterns directly from that tree. It typically needs only two passes over the data instead of one per itemset size, which makes it substantially faster than Apriori on large, dense datasets. When people hit performance walls with Apriori, FP-Growth (or its variant FP-Max) is the usual next step.
In Python, you don't implement either from scratch. The mlxtend library gives you both, plus rule generation, in a few lines:
import pandas as pd
from mlxtend.frequent_patterns import fpgrowth, association_rules
from mlxtend.preprocessing import TransactionEncoder
transactions = [
["bread", "milk", "eggs"],
["bread", "butter"],
["milk", "butter", "eggs"],
["bread", "milk", "butter", "eggs"],
["bread", "milk", "butter"],
]
# one-hot encode baskets into a boolean DataFrame
te = TransactionEncoder()
df = pd.DataFrame(te.fit_transform(transactions), columns=te.columns_)
# find frequent itemsets (support >= 40%)
itemsets = fpgrowth(df, min_support=0.4, use_colnames=True)
# turn them into rules with lift >= 1.0
rules = association_rules(itemsets, metric="lift", min_threshold=1.0)
print(rules[["antecedents", "consequents", "support", "confidence", "lift"]])
Swap fpgrowth for apriori and the rest of the code is identical — a good way to compare the two on your own data.
Scaling out: MapReduce and Spark
When the transaction file no longer fits on one machine, the counting has to be distributed. The classic approach is the SON algorithm (Savasere-Omiecinski-Navathe), which maps cleanly onto MapReduce and is the basis for how big-data frameworks handle this today.
The idea is divide, gather candidates, then verify:
- Split the giant file into chunks, each a fraction
pof the whole. If the global support threshold iss, then within a single chunk you lower it top × s— because any itemset frequent in the entire file must be frequent in at least one chunk. This guarantees no truly frequent itemset is missed. - Mine each chunk independently (using Apriori or FP-Growth locally). The union of everything frequent in any chunk becomes your candidate set.
- Verify the candidates against the full dataset by counting them everywhere and summing the counts.
As two MapReduce passes:
- First Map — each task takes a subset of baskets and finds itemsets frequent within it at the lowered threshold
p × s. It emits(itemset, 1)for each local winner. - First Reduce — collects the keys and outputs the distinct itemsets. This is the candidate list: every itemset that was frequent in at least one chunk.
- Second Map — each task takes the candidate list plus a portion of the data and counts how many times each candidate actually appears in its portion, emitting
(candidate, count). - Second Reduce — sums the counts per candidate across all portions. Any candidate whose total reaches the real threshold
sis genuinely frequent and is emitted; the rest are discarded.
The first pass generates candidates without ever missing a true positive; the second pass filters out the false positives that were frequent locally but not globally. In practice you rarely hand-write this. Apache Spark's MLlib ships a distributed FPGrowth implementation that does the partitioning and counting for you across a cluster — the same two-phase logic, wrapped in a couple of API calls.
Where it pays off
Frequent itemset mining shows up wherever behavior comes in "baskets":
- Retail and e-commerce — product recommendations, cross-sell bundles, store and page layout, promotion design.
- Streaming and content — "watch next" and "read next" from co-viewing patterns.
- Web and product analytics — features used together, common navigation paths, funnel drop-off patterns.
- Fraud and security — combinations of events that co-occur in suspicious sessions.
- Healthcare and bioinformatics — symptoms, diagnoses, or gene expressions that appear together.
The raw material for all of this is clean transactional data, and that is often the actual bottleneck — the algorithms are commodity, but assembling the baskets is not. If your co-purchase or catalog data lives across marketplaces and competitor sites, scraping.pro can collect and structure it for you as a data feed, so your team spends its time mining patterns instead of gathering rows. Combine that with competitor price monitoring and the same association rules can inform bundle pricing, not just recommendations.
FAQ
What's the difference between a frequent itemset and an association rule? A frequent itemset is just a group of items that co-occurs often ({bread, milk}). An association rule adds direction and a strength claim ({bread} → {milk} with 80% confidence). Rules are built from frequent itemsets.
Apriori or FP-Growth — which should I use? FP-Growth is usually faster on large or dense data because it avoids generating candidates. Apriori is simpler to reason about and fine for small datasets or teaching. Both are one function call in mlxtend, so try both.
What support threshold should I set? There is no universal number. Start higher (say 1–5% of baskets) to keep results manageable, then lower it if you are missing interesting-but-rarer combinations. Too low and you drown in noise; too high and you only rediscover the obvious.
Does this need machine learning? No — it is unsupervised pattern mining, not prediction. There is no model to train and no labels required, which is part of why it is so widely used.