摘要:经典的"啤酒与尿布"故事——沃尔玛发现超市里买啤酒的顾客也经常买尿布,于是把这两个商品放在一起,销量大增。这个故事的背后就是关联规则挖掘(Association Rule Mining)。它是无监督学习的一个分支,目标是从事务数据中发现"如果 A 发生了,那么 B 也很有可能发生"这类规律。这篇文章讲清楚关联规则的核心指标、Apriori 算法原理、以及如何用它做电商推荐。


一、什么是关联规则?

购物篮分析

每个顾客的购物篮里有一组商品。关联规则要回答的问题是:

"买 A 的顾客中,有多大比例也买了 B?"

已知一万个购物篮:
  - 买啤酒的: 2000 个
  - 买尿布的: 2500 个
  - 同时买啤酒和尿布的: 1500 个
  
规则:{啤酒} → {尿布}
  支持度:1500/10000 = 15%(两者同时出现的频率)
  置信度:1500/2000 = 75%(买了啤酒的顾客中有 75% 也买了尿布)

关联规则的应用场景

场景 交易 规则示例
电商 购物车 {手机} → {手机壳}
金融 交易流水 {转账} → {登录网银}
医疗 就诊记录 {发烧} → {感冒}
推荐系统 用户行为 {浏览A} → {浏览B}
安全审计 日志 {登录失败3次} → {暴力破解}

二、三个核心指标

支持度(Support)

Support(A → B) = P(A ∩ B) = 同时包含 A 和 B 的交易数 / 总交易数

支持度衡量规则的"普遍性"——一条规则覆盖了多少交易。
   支持度太低 → 规则可能只是巧合
   通常设最小支持度阈值,如 0.01(1%)

置信度(Confidence)

Confidence(A → B) = P(B | A) = Support(A ∩ B) / Support(A) 
                              = 同时买 A 和 B 的交易数 / 买 A 的交易数

置信度衡量规则的"可靠性"——买了 A 的顾客有多大比例也买了 B。
   高置信度 → 规则强
   但高置信度也可能有误导(见下文)

提升度(Lift)

Lift(A → B) = Confidence(A → B) / Support(B) 
            = P(B|A) / P(B)

提升度衡量 A 的出现对 B 的出现是"促进"还是"抑制":
  Lift > 1:A 促进 B(正相关)→ 真正的强规则
  Lift = 1:A 和 B 独立(无关)
  Lift < 1:A 抑制 B(负相关)

为什么需要提升度?

例子:A={买牛奶}, B={买面包}

P(牛奶) = 0.6, P(面包) = 0.7, P(牛奶∩面包) = 0.5

Confidence(牛奶→面包) = 0.5/0.6 = 0.83  ← 很高
Lift(牛奶→面包) = 0.83/0.7 = 1.19       ← 只是略大于1

实际上面包本身就很流行(70% 的人都买),
买牛奶的人中有 83% 买面包——只比平均水平高一点点。

→ 高置信度可能只是因为商品本身畅销,而不是有真正的关联
→ 提升度排除"畅销品偏差",衡量真正的关联强度

三个指标的关系

指标 衡量 越大说明 典型阈值
支持度 规则的普遍性 越多交易符合 0.01~0.1
置信度 规则的可靠性 A→B 的概率越高 0.5~0.8
提升度 规则的显著性 A 和 B 关联越强 >1.5
一条好规则:高支持度 + 高置信度 + 高提升度

例:
  规则:{尿布} → {啤酒}
  支持度 5%, 置信度 60%, 提升度 2.5
  
  解读:
  5% 的顾客同时买了尿布和啤酒(有一定普遍性)
  买尿布的顾客中 60% 也买了啤酒(很可靠)
  买尿布的顾客买啤酒的概率是普通顾客的 2.5 倍(强关联)

三、Apriori 算法

核心思想

Apriori 算法的名字来自拉丁语 "a priori"("来自先前的")。其核心原则是:

如果一个项集是频繁的(支持度 ≥ min_support),
那么它的所有子集也必须是频繁的。

反过来:如果一个项集不频繁,
那么它的所有超集也一定不频繁——可以直接剪枝!
例子:min_support = 0.3

如果 {啤酒, 尿布} 的支持度 = 0.05 < 0.3
→ 不频繁
→ {啤酒, 尿布, 牛奶}、{啤酒, 尿布, 纸巾} 等所有超集
  都不需要再计算——它们一定也不频繁!
  
→ 这种剪枝大幅减少了搜索空间

算法步骤

Apriori 算法(三步走):

第一步:找出所有频繁项集(支持度 ≥ min_support)
  1-项集:{啤酒}{尿布}{牛奶}{面包}...
  2-项集:{啤酒, 尿布}{啤酒, 牛奶}{尿布, 面包}...
  3-项集:{啤酒, 尿布, 面包}...
  直到无法生成更大的频繁项集

第二步:从频繁项集生成所有可能的规则
  频繁项集 {啤酒, 尿布, 面包} 可以生成:
    {啤酒}→{尿布, 面包}
    {啤酒, 尿布}→{面包}
    {面包}→{啤酒, 尿布}
    ...

第三步:筛选出置信度 ≥ min_confidence 的规则
# 伪代码:Apriori
def apriori(transactions, min_support):
    """Apriori 算法"""
    # 1. 生成 1-项集
    frequent_items = {1: find_frequent_1_itemsets(transactions, min_support)}
    
    # 2. 迭代生成更大的项集
    k = 2
    while frequent_items[k-1]:
        # 用 (k-1)-项集生成候选 k-项集
        candidates = generate_candidates(frequent_items[k-1])
        
        # 计算候选集的支持度,筛选
        frequent_items[k] = find_frequent_itemsets(
            candidates, transactions, min_support
        )
        k += 1
    
    return frequent_items

sklearn 没有直接实现 Apriori

需要注意:sklearn 内置算法中没有 Apriori。需要用 mlxtend 库:

# pip install mlxtend
from mlxtend.frequent_patterns import apriori, association_rules
import pandas as pd

四、完整实战:电商购物篮分析

import pandas as pd
from mlxtend.frequent_patterns import apriori, association_rules

# ===== 1. 模拟电商交易数据 =====
# 每条记录是一个购物篮
transactions = [
    ['牛奶', '面包', '鸡蛋'],
    ['面包', '尿布', '啤酒', '鸡蛋'],
    ['牛奶', '尿布', '啤酒', '可乐'],
    ['面包', '牛奶', '尿布', '啤酒'],
    ['面包', '牛奶', '尿布', '可乐'],
    ['面包', '鸡蛋'],
    ['牛奶', '尿布', '啤酒'],
    ['牛奶', '面包', '尿布', '啤酒'],
    ['牛奶', '面包', '鸡蛋', '可乐'],
    ['面包', '尿布', '啤酒'],
]

# ===== 2. 转换成 One-Hot 编码 =====
# Apriori 需要 DataFrame 格式,每列是一个商品,每行是一笔交易
items = sorted(set(item for t in transactions for item in t))
onehot = []

for t in transactions:
    onehot.append([1 if item in t else 0 for item in items])

df = pd.DataFrame(onehot, columns=items)
print("购物篮数据(One-Hot 编码):")
print(df.head())
"""
   可乐  啤酒  尿布  面包  牛奶  鸡蛋
0    0    0    0    1    1    1
1    0    1    1    1    0    1
2    1    1    1    0    1    0
3    0    1    1    1    1    0
4    1    0    1    1    1    0
"""

# ===== 3. Apriori 找出频繁项集 =====
frequent_itemsets = apriori(
    df,
    min_support=0.2,       # 最小支持度 20%
    use_colnames=True,      # 使用商品名而非索引
    max_len=None            # 不限项集大小
)

print(f"\n频繁项集(支持度 ≥ {0.2}):")
print(frequent_itemsets.sort_values('support', ascending=False))
"""
    support            itemsets
0      0.8             (面包)
1      0.6             (牛奶)
2      0.6             (尿布)
3      0.5             (鸡蛋)
4      0.5             (啤酒)
5      0.6          (面包, 牛奶)
6      0.5          (面包, 尿布)
7      0.4          (面包, 鸡蛋)
8      0.5          (牛奶, 尿布)
9      0.4          (牛奶, 啤酒)
10     0.4          (尿布, 啤酒)
11     0.4     (面包, 牛奶, 尿布)
12     0.3     (面包, 牛奶, 啤酒)
13     0.4     (牛奶, 尿布, 啤酒)
14     0.3  (面包, 牛奶, 尿布, 啤酒)
"""

# ===== 4. 生成关联规则 =====
rules = association_rules(
    frequent_itemsets,
    metric='lift',           # 按提升度排序
    min_threshold=1.0        # 只保留提升度 > 1 的规则
)

# 按提升度降序排列
rules = rules.sort_values('lift', ascending=False)

print("\n关联规则(按提升度排序):")
print(rules[['antecedents', 'consequents', 
             'support', 'confidence', 'lift']].round(3).to_string(index=False))
"""
           antecedents        consequents  support  confidence   lift
1            (尿布, 啤酒)           (牛奶)    0.400       1.000  1.667
0            (牛奶, 啤酒)           (尿布)    0.400       1.000  1.667
8            (尿布, 啤酒)       (面包, 牛奶)    0.300       0.750  1.250
5                 (牛奶)           (尿布)    0.500       0.833  1.389
13                (啤酒)           (尿布)    0.400       0.800  1.333
3                 (尿布)         (面包, 牛奶)    0.400       0.667  1.111
...

最强的规则:
  {尿布, 啤酒} → {牛奶}    提升度 = 1.667 ✅
  {牛奶, 啤酒} → {尿布}    提升度 = 1.667 ✅
  → 这三样商品被一起购买的倾向非常强
"""

五、关联规则解读

如何看懂规则

规则:{尿布, 啤酒} → {牛奶}
支持度:0.40 → 40% 的订单同时包含这三样
置信度:1.00 → 买尿布和啤酒的顾客 100% 也买了牛奶
提升度:1.667 → 是随机购买概率的 1.667 倍

结论:
  很可能是"年轻爸爸的周末采购组合"——促销时可以打包推荐

规则筛选建议

业务目标 筛选标准 原因
商品摆放 提升度 > 1.5, 置信度 > 0.5 真正的强关联,值得放在一起
交叉销售 提升度 > 1.2, 支持度 > 0.05 不要太严格,多发现机会
捆绑套餐 提升度 > 2.0, 置信度 > 0.6 强关联才有捆绑价值
个性化推荐 提升度 > 1.0 任何比随机好的关联都可用

几个需要避免的误区

误区 1:高置信度 ≠ 强关联
  → 畅销品本身置信度就高,需要用提升度排除

误区 2:关联 ≠ 因果
  → {啤酒}→{尿布} 不一定是因为因果关系
  → 可能只是"周五晚上年轻爸爸采购"这个隐藏因素

误区 3:稀有但有价值的规则容易被忽略
  → 高价值但低频的组合(如奢侈品关联)
  → 需要降低最小支持度,但会增加计算量

六、FP-Growth:Apriori 的改进

Apriori 的瓶颈

Apriori 需要反复扫描数据库来检查候选集的支持度。当数据量大时,效率很低。

Apriori 的复杂度:
  每次生成新的候选集 → 扫描一次数据库
  如果最大项集长度为 5 → 扫描 5 次
  如果有 10 万笔交易、1 万种商品 → 非常慢

FP-Growth

FP-Growth(Frequent Pattern Growth)通过构建FP-Tree来避免反复扫描:

from mlxtend.frequent_patterns import fpgrowth

# FP-Growth 比 Apriori 快得多(尤其大数据集)
frequent_itemsets_fp = fpgrowth(
    df,
    min_support=0.2,
    use_colnames=True
)

# 速度对比:
# 小数据(<1000 交易):Apriori ≈ FP-Growth
# 中数据(1000-1万):FP-Growth 快 2-5 倍
# 大数据(>1万):Apriori 几乎不可用,FP-Growth 仍然可行
对比 Apriori FP-Growth
扫描数据库次数 多次(=最大项集长度) 2 次
内存占用 大(需要构建树)
小数据集 可用 可用
大数据集 ❌ 慢
实现复杂度 简单 复杂

七、关联规则在推荐系统中的应用

基于关联规则的推荐流程

def recommend_by_rules(rules, purchased_items, top_n=5):
    """
    基于关联规则做推荐
    
    参数:
        rules: 训练好的关联规则
        purchased_items: 用户已购商品列表
        top_n: 推荐数量
    """
    recommendations = {}
    
    for _, rule in rules.iterrows():
        antecedents = set(rule['antecedents'])
        consequents = set(rule['consequents'])
        
        # 如果用户买了规则的前件
        if antecedents.issubset(purchased_items):
            # 规则推荐的后件中,用户还没买的
            new_items = consequents - purchased_items
            for item in new_items:
                if item not in recommendations:
                    recommendations[item] = []
                recommendations[item].append(rule['lift'])
    
    # 按提升度均值排序
    scored = [(item, np.mean(scores)) for item, scores in recommendations.items()]
    scored.sort(key=lambda x: x[1], reverse=True)
    
    return [item for item, _ in scored[:top_n]]

# 使用示例
user_items = {'牛奶', '面包'}
recs = recommend_by_rules(rules, user_items)
print(f"已购: {user_items} → 推荐: {recs}")

关联规则 vs 协同过滤

对比 关联规则 协同过滤
算法类型 无监督 无监督
数据要求 购物篮数据 用户-物品评分矩阵
可解释性 极强("买A的人也买B") ⚠️ 较弱
冷启动 ✅ 可以处理(基于商品而非用户) ❌ 新用户无历史
覆盖率 低(只推荐强关联商品) 高(任何商品都能推荐)
实时性 不支持(需要周期性重新计算) 支持实时增量更新

八、关联规则的局限

局限 说明 缓解方法
数据稀疏性 大部分商品被购买的频率很低 降低最小支持度,或聚合商品类别
规则数量爆炸 10 种商品 → 可能生成数千条规则 用提升度/置信度严格筛选
时效性 关联关系会随时间变化 滑动窗口,只使用近期数据
没有考虑价格 关联规则不考虑商品价格和利润 结合利润加权(高利润商品优先推荐)
只看"买了什么" 不知道用户为什么买 结合用户画像、购买意图分析

九、总结

概念 一句话理解
关联规则 "买 A 的顾客中,有多大比例也买了 B"
支持度 这条规则覆盖了多少数据——普遍性
置信度 这条规则有多可靠——买了 A 后买 B 的概率
提升度 这对商品是不是真的有关联——排除畅销品偏差
Apriori 通过剪枝高效搜索频繁项集的算法
FP-Growth 用树结构替代多次扫描的 Apriori 改进版

核心三句话

  1. 关联规则是最容易理解的 ML 算法之一——"买 A 的人也买 B",业务人员一眼就能看懂
  2. 提升度比置信度更重要——高置信度可能只是因为商品本身畅销,提升度才能告诉你真正的强关联
  3. Apriori 适合小数据,FP-Growth 适合大数据——数据量大时 Apriori 的性能会急剧下降
Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐