一、先把场景立起来
想象超市 POS 机刷出来的一张张小票:
|
T1 |
牛奶, 面包, 黄油 |
|
T2 |
牛奶, 面包 |
|
T3 |
面包, 黄油 |
|
T4 |
牛奶, 面包, 黄油, 鸡蛋 |
|
T5 |
面包, 鸡蛋 |
一共 5 笔交易。下面所有概念都围着这张表转。
二、四个基本概念(用上面那张表对号入座)
-
项 (Item):最小单位,比如"牛奶""面包"。
-
项集 (Itemset):项的组合。{牛奶} 是 1-项集,{牛奶, 面包} 是 2-项集。
-
事务 (Transaction):一笔交易里实际出现的项集(T1 那一行)。
-
总事务数记作 N = 5(后面算支持度要用)。
三、支持度 (Support) —— "出现有多频繁"
公式(项集版,最常用)
Sup(X)=N包含项集 X 的事务数
💡 注意:支持度是对项集定义的,不是对规则。规则 A⇒B 的支持度其实就是项集 {A,B} 的支持度。
用上面那张表算几个:
-
Sup({牛奶}) = 3/5 = 60%(T1,T2,T4 有)
-
Sup({面包}) = 5/5 = 100%
-
Sup({黄油}) = 3/5 = 60%
-
Sup({牛奶, 面包}) = 3/5 = 60%(T1,T2,T4)
意义:支持度像"人气值",先筛掉太冷门的东西(比如"同时买牙膏和轮胎"才 0.1%,没分析价值)。
四、关联规则 A⇒B
规则形式:A ⇒ B(A 叫前件/左部,B 叫后件/右部,A∩B=∅)
一条规则好不好,通常用两个指标:
1. 置信度 (Confidence) —— "可信度"
Conf(A⇒B)=Sup(A)Sup(A∪B)=P(B∣A)
翻译成人话:买 A 的人里,有多大比例也买了 B。
例:算 {牛奶}⇒{面包}
-
Sup({牛奶,面包}) = 3/5
-
Sup({牛奶}) = 3/5
-
Conf = (3/5)/(3/5) = 100%
意思是:买牛奶的 3 个人(T1,T2,T4)全买了面包 → 这条规则"很铁"。
再算 {黄油}⇒{牛奶}:
-
Sup({黄油,牛奶}) = 2/5(T1,T4)
-
Sup({黄油}) = 3/5
-
Conf = 2/3 ≈ 66.7%
2. 提升度 (Lift) —— "是不是真有关系"
Lift(A⇒B)=Sup(A)⋅Sup(B)Sup(A∪B)=Sup(B)Conf(A⇒B)
Lift 用来排除"假关联"——A 和 B 本来就各自都热门,凑一起只是巧合。
-
Lift = 1:A 和 B 独立,规则没意义(纯巧合)
-
Lift > 1:正相关,A 出现能"拉动"B(越好)
-
Lift < 1:负相关,买 A 反而抑制 B
例:{牛奶}⇒{面包}
-
Sup({牛奶,面包}) = 3/5 = 0.6
-
Sup({牛奶})·Sup({面包}) = 0.6 × 1.0 = 0.6
-
Lift = 0.6 / 0.6 = 1 → 哦?这条虽然 conf 100%,但面包本身 100% 出现,牛奶没"拉动"作用,其实挺平凡。
再算 {牛奶}⇒{黄油}:
-
Sup({牛奶,黄油}) = 2/5 = 0.4
-
Sup({牛奶})·Sup({黄油}) = 0.6 × 0.6 = 0.36
-
Lift = 0.4 / 0.36 ≈ 1.11 > 1 → 这才是有正拉动的规则。
📌 大题常考 Lift 的判断:"Lift > 1 才有挖掘价值"。
五、Apriori 算法(大题核心)
为什么要 Apriori?
如果超市有 1000 种商品,枚举所有项集是 2¹⁰⁰⁰ 量级,炸了。Apriori 用一条先验原理来剪枝:
🔑 频繁项集的所有非空子集一定频繁;反之,只要有一个子集不频繁,该项集一定不频繁。
逆否命题更有用:如果 {牛奶,面包} 都不频繁,那 {牛奶,面包,黄油} 根本不用算,直接扔。
算法两步走(每一轮 k 都重复)
连接步 (Join):用两个 (k-1)-频繁项集拼成候选 k-项集(要求前 k-2 项相同,第 k-1 项不同)
剪枝步 (Prune):对候选 k-项集,检查它的所有 (k-1)-子集是否都在 (k-1)-频繁表里,不在的就删掉
扫一遍数据库,算剩下候选的支持度,筛出 ≥ min_sup 的,成为 k-频繁项集
拿上面的表手推一遍(设 min_sup = 60%,即至少出现 3 次)
k=1:1-项集
|
{牛奶} |
3 |
60% |
✅ |
|
{面包} |
5 |
100% |
✅ |
|
{黄油} |
3 |
60% |
✅ |
|
{鸡蛋} |
2 |
40% |
❌ |
频繁 1-项集 L₁ = {牛奶, 面包, 黄油}
k=2:2-项集
-
连接:从 L₁ 两两拼 → C₂ = { {牛奶,面包}, {牛奶,黄油}, {面包,黄油} }
-
剪枝:这三个的 1-子集全在 L₁ 里,都留着
-
扫库算 sup:
-
{牛奶,面包}:T1,T2,T4 → 3 ✅
-
{牛奶,黄油}:T1,T4 → 2 ❌(<3,淘汰)
-
{面包,黄油}:T1,T3,T4 → 3 ✅
-
L₂ = { {牛奶,面包}, {面包,黄油} }
k=3:3-项集
-
连接:{牛奶,面包} 和 {面包,黄油} 拼 → {牛奶,面包,黄油}
-
剪枝:检查它的 2-子集:{牛奶,黄油} 不在 L₂ 里 → 直接砍掉!
-
C₃ 空了,算法停。
最终频繁项集:L₁ + L₂ 那几个。
✨ 剪枝的威力就在这:{牛奶,面包,黄油} 明明在 T1、T4 出现了 2 次,但因为 {牛奶,黄油} 不频繁,Apriori 连算都不算它,直接丢弃(当然这里即使算也不够 min_sup,但大数据下剪枝能省海量 IO)。
k=3 为什么 {牛奶,黄油} 要查?
{牛奶,面包,黄油} 的所有 2-子集是:
-
{牛奶,面包} ✅ 在 L₂
-
{牛奶,黄油} ❌ 不在 L₂ → 触发剪枝,整个 3-项集拜拜
这就是先验原理的落地:父集要想频繁,所有子集必须先频繁。
六、大题答题套路(重点)
题目一般会给你若干交易 + 一个 min_sup,让你:
找所有频繁项集 → 按 Apriori 走 k=1,2,3…,每轮写 Cₖ、剪枝、Lₖ
由频繁项集生成关联规则 → 对每个频繁项集(长度≥2),枚举它的所有非空真子集 A,规则 A⇒(项集-A),算 Conf
算 Support / Confidence / Lift → 套三个公式,注意 Lift 要判断 >1/<1/=1
可能让你筛:比如"只保留 Conf ≥ 80% 且 Lift > 1 的规则"
易错点提醒(新手必踩)
-
❌ 支持度分母是总事务数 N,不是"含 A 的事务数"(那是条件概率分母)
-
❌ Conf(A⇒B) ≠ Conf(B⇒A),方向不能颠倒
-
❌ Lift = 1 不代表规则错,只是"独立",挖掘意义不大
-
❌ Apriori 剪枝查的是所有 (k-1)-子集,不是只查两个母集那俩

