提到关联规则,大家可能会想到那个经典的 “啤酒和尿布” 案例:超市通过分析交易数据,发现男性顾客经常在买尿布时顺便买啤酒,于是调整货架摆放,提升了销量。这就是关联规则挖掘的实际应用 —— 从海量数据中找出事物之间隐藏的关联关系。不过 我也看到这个故事好像是商家编出来的故事~~~
一、关联规则挖掘概述
首先,我们得明确什么是 “关联”。关联反映的是数据集中项目之间的相互依赖关系,比如 “购买面包的顾客同时购买牛奶” 就是一种关联。而关联规则挖掘,就是从数据中发现这种 “频繁出现的模式”,并形成类似 “如果 A,那么 B”(A→B)的规则。
1. 基本概念
最核心的数据形式是事务数据,比如超市的交易记录:每条记录(事务)有一个唯一标识(TID),包含多个项目(比如商品)。例如 {TID:10, 项目:A,C,D} 就表示一次购买了 A、C、D 三种商品。
2. 挖掘目标与步骤
关联规则挖掘的最终目标是找到 “强关联规则”,也就是满足最小支持度(规则出现的频率)、最小置信度(规则的可靠程度)和提升度阈值的规则。整个过程分两步:
- 第一步:产生所有 “频繁项集”—— 即出现频率不低于最小支持度的项目集合(比如频繁 1 项集是单个高频商品,频繁 2 项集是高频的商品对);
- 第二步:从频繁项集中生成强关联规则 —— 通过计算置信度、提升度,筛选出可靠的规则(比如 “购买 A→购买 B” 的置信度是否达标)。
二、Apriori 算法
第一个要重点掌握的是 Apriori 算法,它是关联规则挖掘的经典算法,由 Agrawal 和 R.Srikant 在 1994 年提出。它的核心是 “自下而上找频繁项集,再生成规则”,效率提升的关键是 “先验原理”。
1. 先验原理:简化搜索的核心
先验原理可以概括为:如果一个项集是频繁的,那么它的所有子集也是频繁的;反过来,如果一个项集是非频繁的,那么它的所有超集也一定是非频繁的。
比如,如果 “{A,B}” 不是频繁项集(支持度低于阈值),那么包含它的 “{A,B,C}”“{A,B,D}” 等也一定不是频繁项集,这样就可以提前 “剪枝”,减少计算量。
2. 频繁项集的产生过程
Apriori 通过 “连接 - 剪枝” 循环,从频繁 1 项集开始逐层生成更高阶的频繁项集:
- 步骤 1:扫描数据,计算所有单个项目的支持度,筛选出频繁 1 项集(L₁);
- 步骤 2:将 L₁中的项集两两连接,生成候选 2 项集(C₂),再用先验原理剪枝(去掉包含非频繁子集的候选集);
- 步骤 3:扫描数据计算 C₂的支持度,筛选出频繁 2 项集(L₂);
- 重复以上步骤,直到无法生成新的频繁项集为止。
举个例子:假设最小支持度是 0.5,交易数据有 4 条记录。首先找到频繁 1 项集(比如 {B,C,E},支持度都≥0.5);然后连接生成候选 2 项集 { B,C },{ B,E },{ C,E },计算支持度后筛选出频繁 2 项集;再继续生成 3 项集,直到没有符合条件的项集。
3. 从频繁项集生成关联规则
有了频繁项集,怎么生成规则呢?比如对频繁 3 项集 {B,C,E},可以分解出所有可能的规则:
- B→C,E;C→B,E;E→B,C;
- B,C→E;B,E→C;C,E→B。
然后计算每条规则的置信度(比如 “B,C→E” 的置信度 = 支持度 ({B,C,E})/ 支持度 ({B,C})),保留置信度≥最小阈值的规则。同样,这里也可以用先验原理剪枝:如果某条规则的置信度不达标,那么包含它的更长规则也无需考虑。
4. Python 实现:用 mlxtend 库快速上手
实际操作中,我们不用手动写算法,mlxtend 库已经帮我们实现了。步骤如下:
- 安装库:pip install mlxtend;
- 数据预处理:用TransactionEncoder将交易数据转为 0/1 编码的 DataFrame(比如某条交易包含 A,就标记 A 为 1,否则为 0);
- 挖掘频繁项集:调用apriori()函数,设置最小支持度(比如min_support=0.5);
- 生成关联规则:用association_rules()函数,指定评价指标(比如置信度)和阈值(比如min_threshold=0.5)。
比如对包含 {A,C,D}、{B,C,E} 等交易的数据,通过以上步骤就能快速得到类似 “C→E”“B→E” 的强关联规则。
三、FP-growth 算法
Apriori 算法虽然经典,但需要多次扫描数据、生成大量候选集,效率在大数据场景下会受影响。于是韩家炜教授在 2000 年提出了 FP-growth 算法,它的优势是:无需生成候选集,只需扫描数据 2 次,用 “频繁模式树(FP-tree)” 压缩存储数据,效率更高。
1. 核心步骤:构建 FP-tree 与挖掘频繁项集
FP-growth 的过程分两步:构建 FP-tree,再从树中挖掘频繁项集。
(1)构建 FP-tree
- 第一步:第一次扫描数据,统计所有项目的支持度,筛选出频繁 1 项集,并按支持度降序排序(比如 {B:3, C:3, E:3, A:2},支持度越高越靠前);
- 第二步:第二次扫描数据,按排序后的顺序重新整理每条交易(去掉非频繁项),然后逐条插入 FP-tree:
- 树的根节点为 {NULL},每条交易对应一条路径,路径上的节点记录支持度计数(比如包含 {B,C,E} 的交易,会让 B、C、E 的计数各 + 1);
- 同时维护一个 “项头表”,记录每个项目的支持度和在树中的链接指针,方便后续查找。
比如 4 条交易数据处理后,FP-tree 会压缩存储所有频繁项的关联关系,像 {B,C,E} 出现多次,对应的路径会共享节点,减少冗余。
(2)挖掘 FP-tree:递归生成条件 FP-tree
有了 FP-tree,怎么找频繁项集呢?核心是 “分而治之”,通过生成 “条件模式基” 和 “条件 FP-tree” 递归挖掘:
- 条件模式基:对每个频繁项(比如 A),从项头表找到它在树中的所有路径,这些路径去掉 A 后就是 A 的条件模式基(反映 “哪些项目常和 A 一起出现”);
- 条件 FP-tree:用条件模式基构建新的 FP-tree(只保留满足最小支持度的项目);
- 递归挖掘:对条件 FP-tree 重复上述过程,直到树为空,所有过程中出现的 “后缀项集” 就是频繁项集。
比如挖掘 {A} 的频繁项集时,先找到 A 的条件模式基,构建条件 FP-tree,再从这个树中挖掘包含 A 的更长项集(如 {C,A}),直到无法生成新树为止。
(3)Python 实现:和 Apriori 用法相似
mlxtend 库同样提供了 FP-growth 的实现,函数是fpgrowth(),参数和apriori()一致(需要 0/1 编码的 DataFrame,设置min_support等)。对于同样的零售数据集,用fpgrowth()能更快得到频繁项集,再结合association_rules()生成规则即可。
四、Eclat 算法
最后简单介绍 Eclat 算法,它和前两种算法的思路不同:基于 “垂直数据格式”(记录每个项目出现的事务 ID 列表),采用深度优先搜索,通过计算项目集的 “支持度交集”(共同出现的事务数)来挖掘频繁项集。它的优势是处理高维数据时效率较高,但由于 PPT 中未展开细节,大家只需了解其核心是 “垂直格式 + 交集计算” 即可。
总结
Apriori 算法是基础,通过先验原理剪枝;FP-growth 算法更高效,用 FP-tree 压缩数据;Eclat 算法则从垂直角度处理数据。实际应用中,大家可以根据数据量和维度选择合适的算法,而 mlxtend 库能帮我们快速实现这些算法。
关联规则挖掘的价值在于 “发现未知关联”,除了零售行业,它还能用于医疗(疾病与症状关联)、推荐系统(用户行为与商品关联)等领域。