关联规则挖掘(Association Rule Mining)是数据挖掘的经典方法,目标是从交易数据中发现物品之间的关联关系。最著名的案例是"啤酒与尿布"——沃尔玛发现啤酒和尿布经常被一起购买。
| 概念 | 定义 | 含义 |
|---|---|---|
| 支持度 | sup(A)=包含A的交易数/总交易数 | A出现的频繁程度 |
| 置信度 | conf(A→B)=sup(A∪B)/sup(A) | 买A后买B的概率 |
| 提升度 | lift(A→B)=conf(A→B)/sup(B) | A对B的提升程度,>1正相关 |
| 维度 | Apriori | FP-Growth |
|---|---|---|
| 扫描次数 | 多次(每层一次) | 2次 |
| 候选项集 | 需生成大量候选 | 无需显式生成候选 |
| 空间 | 候选项集可能爆炸 | FP-Tree压缩存储 |
| 适用场景 | 候选项集较少 | 数据量大、模式密集 |
sup(A) = |包含A的交易| / |总交易|
conf(A→B) = sup(A∪B) / sup(A)
lift(A→B) = conf(A→B) / sup(B)
lift>1: 正相关; lift=1: 无关; lift<1: 负相关
若项集X不频繁,则X的超集也不频繁
import numpy as np
from collections import defaultdict
from itertools import combinations
np.random.seed(42)
print("="*60+"\n关联规则推荐系统\n"+"="*60)
# 模拟交易数据
n_transactions=200;n_items=20
items=[f"I{j}"for j in range(n_items)]
transactions=[]
for _ in range(n_transactions):
n=np.random.poisson(4)+1
t=set(np.random.choice(items,size=min(n,n_items),replace=False))
transactions.append(t)
print(f"交易数:{len(transactions)} 物品数:{n_items}")
print(f"平均每笔交易物品数:{np.mean([len(t)for t in transactions]):.1f}")
# Apriori算法
def apriori(transactions,min_support=0.05):
n=len(transactions)
# 频繁1-项集
item_counts=defaultdict(int)
for t in transactions:
for item in t:item_counts[frozenset([item])]+=1
freq={k:v/n for k,v in item_counts.items() if v/n>=min_support}
all_freq=dict(freq)
k=2
while freq:
# 生成候选项集
items_list=list(freq.keys())
candidates=set()
for i in range(len(items_list)):
for j in range(i+1,len(items_list)):
union=items_list[i]|items_list[j]
if len(union)==k:candidates.add(union)
# 计算支持度
new_freq={}
for cand in candidates:
count=sum(1 for t in transactions if cand.issubset(t))
sup=count/n
if sup>=min_support:new_freq[cand]=sup
all_freq.update(new_freq)
freq=new_freq
k+=1
return all_freq
freq_items=apriori(transactions,min_support=0.05)
print(f"\nApriori频繁项集数:{len(freq_items)}")
print("Top-10频繁项集:")
for itemset,sup in sorted(freq_items.items(),key=lambda x:-x[1])[:10]:
print(f" {set(itemset)}: 支持度={sup:.4f}")
# 生成关联规则
def gen_rules(freq_items,min_confidence=0.5):
rules=[]
for itemset,sup in freq_items.items():
if len(itemset)<2:continue
for i in range(1,len(itemset)):
for antecedent in combinations(itemset,i):
antecedent=frozenset(antecedent)
consequent=itemset-antecedent
if antecedent in freq_items:
confidence=sup/freq_items[antecedent]
if confidence>=min_confidence:
lift=confidence/freq_items.get(consequent,0.001)
rules.append((antecedent,consequent,confidence,lift,sup))
return rules
rules=gen_rules(freq_items,min_confidence=0.3)
print(f"\n关联规则数:{len(rules)}")
print("Top-10关联规则(按置信度):")
for ant,cons,conf,lift,sup in sorted(rules,key=lambda x:-x[2])[:10]:
print(f" {set(ant)}=>{set(cons)}: 置信度={conf:.4f} 提升度={lift:.4f}")
# FP-Growth
class FPNode:
def __init__(self,item,count=1,parent=None):
self.item=item;self.count=count;self.parent=parent;self.children={}
def add_count(self,n=1):self.count+=n
def build_fptree(transactions,min_support=0.05):
n=len(transactions)
item_counts=defaultdict(int)
for t in transactions:
for item in t:item_counts[item]+=1
freq_items={k:v for k,v in item_counts.items() if v/n>=min_support}
if not freq_items:return None,{}
root=FPNode(None,0)
header=defaultdict(list)
for t in transactions:
items_sorted=[item for item in sorted(t,key=lambda x:-freq_items.get(x,0))if item in freq_items]
node=root
for item in items_sorted:
if item in node.children:
node.children[item].add_count()
else:
new_node=FPNode(item,1,node)
node.children[item]=new_node
header[item].append(new_node)
node=node.children[item]
return root,header
tree,header=build_fptree(transactions)
print(f"\nFP-Tree节点数:{sum(len(v)for v in header.values())}")
print(f"FP-Tree频繁物品数:{len(header)}")
# 推荐应用
print("\n基于关联规则的推荐:")
target_item="I0"
target_rules=[(ant,cons,conf,lift)for ant,cons,conf,lift,_ in rules if target_item in ant]
recommendations=sorted([(list(cons)[0],conf)for _,cons,conf,_ in target_rules],key=lambda x:-x[1])
print(f"购买了{target_item}的推荐:")
for item,conf in recommendations[:5]:
print(f" {item}: 置信度={conf:.4f}")
# 评估
print("\n评估:")
total_rules=len(rules)
avg_conf=np.mean([r[2]for r in rules])if rules else 0
avg_lift=np.mean([r[3]for r in rules])if rules else 0
print(f"规则数:{total_rules} 平均置信度:{avg_conf:.4f} 平均提升度:{avg_lift:.4f}")
✅ 验证通过
本课代码涵盖了从数据生成、模型训练到效果评估的完整流程。以下是关键步骤的详细解读:
代码设计原则:简洁可读、关键步骤有注释、结果可复现(固定随机种子)。
| 组件 | 版本 | 说明 |
|---|---|---|
| Python | 3.8+ | 推荐3.10版本 |
| NumPy | 1.21+ | 核心数值计算库 |
| SciPy | 1.7+ | 统计检验(部分课程) |
本课是第5课:关联规则推荐,属于基础方法阶段。我们系统学习了本课的核心概念、数学原理和代码实现,并通过实机运行验证了算法的正确性。
练习1:调整min_support从0.05改为0.03/0.1,观察规则数变化
练习2:实现FP-Growth的完整挖掘过程
练习3:计算所有规则的 conviction 指标
练习4:实现基于时序的关联规则(考虑购买顺序)
| 公司 | 场景 | 核心技术 |
|---|---|---|
| 字节跳动 | 抖音/TikTok | 多目标排序+实时特征+双塔召回 |
| 阿里巴巴 | 淘宝推荐 | DIN/DIEN序列模型+MIND多兴趣 |
| 腾讯 | 微信看一看 | DeepFM+图神经网络召回 |
| 美团 | 本地生活推荐 | 多场景多目标+时空特征 |
| Netflix | 视频推荐 | 矩阵分解+深度学习混合 |
✅ 理解关联规则挖掘的核心概念与度量
✅ 掌握Apriori算法的原理与实现
✅ 理解FP-Growth的优化思路
✅ 掌握关联规则在推荐系统中的应用场景