Apriori 关联规则:购物篮分析
关联规则与购物篮分析
关联规则(Association Rules)用于发现数据集中项与项之间有趣的关系。最经典的应用场景是购物篮分析:通过分析顾客一次购物中同时购买的商品组合,挖掘出类似“购买尿布的顾客很可能也会购买啤酒”这样的商品关联,从而优化货架摆放、交叉销售和推荐系统。
购物篮数据通常表示为事务数据库,每一行记录为一个事务(一笔订单),包含该次购买的所有商品。
核心度量指标
关联规则的形式为 X → Y,其中 X 和 Y 是不相交的项集。衡量规则强弱的三个关键指标:
1. 支持度(Support)
项集在总事务中出现的频率。
- 项集支持度:
support(X) = 包含X的事务数 / 总事务数 - 规则支持度:
support(X → Y) = support(X ∪ Y)
支持度反映了规则的普遍性,支持度过低的规则可能只是偶然现象。
2. 置信度(Confidence)
在包含 X 的事务中,同时也包含 Y 的概率。
confidence(X → Y) = support(X ∪ Y) / support(X)
置信度衡量规则的可靠性,但高置信度并不代表规则有意义。例如,如果 Y 本身非常热门,即使 X 与 Y 无关,置信度也可能很高。
3. 提升度(Lift)
衡量 X 和 Y 之间的相关性强度。
lift(X → Y) = confidence(X → Y) / support(Y) = support(X ∪ Y) / (support(X) * support(Y))
- 提升度 > 1:正相关,X 的出现提升了 Y 出现的概率
- 提升度 = 1:X 与 Y 独立,规则无实际价值
- 提升度 < 1:负相关,X 的出现降低了 Y 出现的概率
提升度弥补了置信度的缺陷,是筛选有效规则的关键指标。
Apriori 算法原理
关联规则挖掘面临的首要问题是如何高效地从海量组合中找出所有频繁项集(满足最小支持度的项集)。暴力穷举会产生组合爆炸,例如有 d 个不同商品,可能的项集数量为 2^d - 1。
Apriori 算法利用**先验性质(Apriori Principle)**进行剪枝:
一个项集是频繁的,那么它的所有子集也必须是频繁的。等价逆否命题:如果一个项集的某个子集非频繁,则该项集也一定非频繁。
基于这一性质,Apriori 采用逐层搜索的迭代方法:
- 从频繁 1-项集开始
- 由频繁 k-项集生成候选 (k+1)-项集
- 扫描数据库对候选集计数,剔除低于最小支持度的项集
- 重复直到无法生成新的频繁项集
算法步骤详解
输入:事务数据库 D,最小支持度阈值 min_sup,最小置信度阈值 min_conf
输出:所有满足条件的关联规则
第一步:生成频繁项集
- 扫描 D,统计每个单项的支持度,得到频繁 1-项集 L₁。
- 记 k = 1。
- 连接步(Join):由 Lₖ 生成候选 (k+1)-项集 Cₖ₊₁。连接条件:两个频繁 k-项集,如果它们的前 (k-1) 项相同,则可连接。
- 剪枝步(Prune):对 Cₖ₊₁ 中的每个候选项集,检查其所有 k-子集是否都在 Lₖ 中;若存在任一子集非频繁,则将该候选项集删除。
- 扫描 D,计算 Cₖ₊₁ 中每个候选项集的支持度,保留满足 min_sup 的项集,形成 Lₖ₊₁。
- k = k + 1,重复步骤 3-5,直到无法生成新的 Lₖ。
- 全部频繁项集的集合为 ∪ Lₖ。
第二步:由频繁项集生成关联规则
对于每个频繁项集 F 及其非空子集 A:
- 计算规则
A → (F - A)的置信度 - 若
confidence ≥ min_conf且提升度通常 > 1(可设置 lift 阈值进一步筛选),则输出该规则
为进一步提高效率,可以利用置信度的反单调性:对于同一个频繁项集 F,若规则 A → (F - A) 置信度不达标,则任何 A' ⊂ A 的规则 A' → (F - A') 置信度必然更低(因为分母 support(A') 更大),可直接剪枝。
实战示例:手工计算 Apriori
考虑以下 5 笔购物事务,最小支持度设为 0.4(即至少出现在 2 个事务中),最小置信度 0.6。
| 事务ID | 商品列表 |
|---|---|
| T1 | 牛奶, 面包, 尿布 |
| T2 | 牛奶, 尿布, 啤酒, 鸡蛋 |
| T3 | 面包, 啤酒, 鸡蛋 |
| T4 | 牛奶, 面包, 尿布, 啤酒 |
| T5 | 牛奶, 面包, 啤酒 |
生成频繁项集:
L₁(频繁 1-项集): 扫描计数:牛奶:4, 面包:4, 尿布:3, 啤酒:4, 鸡蛋:2。全部 ≥2,均为频繁。
C₂(候选 2-项集): 由 L₁ 连接得到 10 个组合,扫描计数并过滤 ≥2:
- {牛奶,面包}:4, {牛奶,尿布}:3, {牛奶,啤酒}:3, {牛奶,鸡蛋}:1 (删除)
- {面包,尿布}:2, {面包,啤酒}:3, {面包,鸡蛋}:1 (删除)
- {尿布,啤酒}:2, {尿布,鸡蛋}:1 (删除)
- {啤酒,鸡蛋}:2 L₂:{牛奶,面包}, {牛奶,尿布}, {牛奶,啤酒}, {面包,尿布}, {面包,啤酒}, {尿布,啤酒}, {啤酒,鸡蛋}
C₃(候选 3-项集): 由 L₂ 连接:
- {牛奶,面包} 与 {牛奶,尿布} → 候选 {牛奶,面包,尿布}。检查其2-子集:{牛奶,面包}∈L₂,{牛奶,尿布}∈L₂,{面包,尿布}∈L₂,通过剪枝。
- {牛奶,面包} 与 {牛奶,啤酒} → {牛奶,面包,啤酒},子集全部频繁。
- {牛奶,尿布} 与 {牛奶,啤酒} → {牛奶,尿布,啤酒},子集全部频繁。
- {面包,尿布} 与 {面包,啤酒} → {面包,尿布,啤酒},子集全部频繁。
- {尿布,啤酒} 与 {啤酒,鸡蛋} → 前 (k-1)=1 项不同(尿布 vs 啤酒),不满足连接条件。 扫描 C₃ 计数(仅列出存在的事务):
- {牛奶,面包,尿布}: T1,T4 → 2 次
- {牛奶,面包,啤酒}: T4,T5 → 2 次
- {牛奶,尿布,啤酒}: T2,T4 → 2 次
- {面包,尿布,啤酒}: T4 单独出现1次,删除。 L₃:{牛奶,面包,尿布}, {牛奶,面包,啤酒}, {牛奶,尿布,啤酒}
C₄(候选 4-项集): 由 L₃ 连接:前 2 项均为 {牛奶,面包} 的只有 {牛奶,面包,尿布} 和 {牛奶,面包,啤酒},连接得 {牛奶,面包,尿布,啤酒}。检查3-子集:{牛奶,面包,尿布}、{牛奶,面包,啤酒}、{牛奶,尿布,啤酒} 都在 L₃ 中,但 {面包,尿布,啤酒} 不在 L₃。剪枝删除。频繁项集生成结束。
生成规则: 以频繁 3-项集 {牛奶,面包,尿布} (支持度=2/5=0.4) 为例,列出非空子集 A:
- A={牛奶} → {面包,尿布}:conf = 2/4=0.5 <0.6 ✗
- A={面包} → {牛奶,尿布}:conf = 2/4=0.5 <0.6 ✗
- A={尿布} → {牛奶,面包}:conf = 2/3≈0.67 ≥0.6 ✓
- A={牛奶,面包} → {尿布}:conf = 2/4=0.5 ✗
- A={牛奶,尿布} → {面包}:conf = 2/3≈0.67 ✓
- A={面包,尿布} → {牛奶}:conf = 2/2=1.0 ✓
同理处理其他频繁项集。再计算提升度过滤无用规则。例如 {面包,尿布} → {牛奶}:lift = 1.0 / support(牛奶) = 1.0 / (4/5) = 1.25 >1,有效规则。
参数选择与调优
- 最小支持度:设置过高会遗漏有价值的长尾规则;设置过低则产生海量频繁项集,计算量大且可能包含大量无意义的“常识”规则。通常根据数据量和业务需求试验调整,零售领域常设置 0.1%~1% 的事务占比。
- 最小置信度:反映规则可靠性,一般设为 0.5~0.9 之间。但必须结合提升度使用,因为热门商品会导致高置信低关联的伪规则。
- 最小提升度:通常选取 > 1,例如 1.2 以上,确保规则具有正向提升效果。
- 数据预处理:购物篮数据常常稀疏,应考虑品类聚合成大类(如“饮料”而非具体品牌),或去除过于热门的单品(如购物袋)以避免它们稀释有效规则。
应用场景与局限性
应用场景:
- 零售交叉销售与货架布置
- 电商推荐系统(“购买了该商品的用户还购买了...”)
- 医疗诊断(症状与疾病关联)
- 网络入侵检测(事件序列关联)
局限性:
- 计算复杂度仍较高,不适合超大规模高维数据
- 仅考虑共现频率,忽略商品价值、时序、数量等信息
- 产生大量规则,多数无趣,需要后处理(如规则兴趣度度量)
对于更高效的需求,可考虑 FP-Growth 算法(不产生候选项集),或使用分布式框架(Spark MLlib 中的关联规则模块)处理大规模数据。
Python 快速实现
使用 mlxtend 库可快速应用 Apriori 算法:
import pandas as pd
from mlxtend.preprocessing import TransactionEncoder
from mlxtend.frequent_patterns import apriori, association_rules
# 原始事务数据
dataset = [
['牛奶', '面包', '尿布'],
['牛奶', '尿布', '啤酒', '鸡蛋'],
['面包', '啤酒', '鸡蛋'],
['牛奶', '面包', '尿布', '啤酒'],
['牛奶', '面包', '啤酒']
]
# 转换为 one-hot 编码
te = TransactionEncoder()
te_ary = te.fit(dataset).transform(dataset)
df = pd.DataFrame(te_ary, columns=te.columns_)
# 挖掘频繁项集
frequent_itemsets = apriori(df, min_support=0.4, use_colnames=True)
# 生成关联规则
rules = association_rules(frequent_itemsets, metric="confidence", min_threshold=0.6)
# 筛选提升度 > 1 的规则
valid_rules = rules[rules['lift'] > 1]
print(valid_rules[['antecedents', 'consequents', 'support', 'confidence', 'lift']])
通过调整 min_support 和 min_threshold 即可灵活控制规则产出。输出结果清晰展示前件、后件及各项指标,便于后续业务解读。