恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
关联规则算法核心解析:Apriori与FP-Growth实战指南
首页
资讯中心
/
关联规则算法核心解析:Apriori与FP-Growth实战指南
关联规则算法核心解析:Apriori与FP-Growth实战指南
发布时间:2026/10/14 15:54:06
关联规则算法总结做数据分析这几年接触过的挖掘算法不少但关联规则一直是我觉得“入门容易、做好很难”的一类。说它入门容易是因为Apriori的原理半小时就能讲清楚说它做好很难是因为一旦上了真实业务数据——动不动几十万条订单、几千个SKU——支持度怎么设、置信度怎么看、规则怎么筛选全都变成经验活。这篇文章我把这块内容系统整理一遍从核心概念到算法实现从代码演示到调参踩坑给需要用它做购物篮分析、交叉销售推荐、捆绑营销的朋友一份可以直接参考的笔记。适合正在学习数据挖掘的初学者也适合项目里准备落地关联规则的分析师。1. 关联规则的核心概念与度量指标1.1 什么是关联规则关联规则说白了就是找“一起出现”的模式。最经典的例子就是超市购物篮顾客买了A商品有多大可能也会买B商品这个A和B的共现关系就是一条关联规则的核心内容。规则本身用蕴含式表示比如{尿布} → {啤酒}含义是在某个交易集合里买了尿布的顾客中有相当比例的人同时买了啤酒。通过分析大量交易记录算法自动挖掘出类似这样的强规则然后业务方就可以据此做商品捆绑、货架摆放、优惠券跨品类推荐等等。关联规则处理的数据形态比较特别不是传统的数值型表格而是“事务型数据”。每一行是一笔订单订单里面是一个商品集合。比如订单1牛奶、面包、鸡蛋订单2面包、尿布、啤酒、鸡蛋订单3牛奶、尿布、啤酒、面包每笔订单的商品数和商品种类都不固定这种“不定长集合”数据正是关联规则的用武之地。1.2 三个核心指标支持度、置信度、提升度判断一条规则好不好不能光凭直觉“看着挺像那么回事”必须用指标说话。关联规则领域有三大标准度量分别是支持度、置信度和提升度。这三个指标我一个个说清楚因为后面算法的每一步优化都和它们有关。支持度Support支持度衡量的是一个项集在全部交易中出现的频次公式是[ Support(X) \frac{包含X的交易数}{总交易数} ]比如总共有100笔订单其中20笔包含了“牛奶”那{牛奶}的支持度就是20%。支持度体现了“覆盖面”。一条规则的左侧项集支持度太低说明它只适用于极少数场景业务上一般没太多可操作性。所以几乎所有关联规则算法第一步都是过滤支持度——先找出那些出现次数足够多的频繁项集再在频繁项集基础上生成规则。置信度Confidence置信度描述的是条件概率买了X的顾客中有多少比例也会买Y。公式[ Confidence(X \Rightarrow Y) \frac{同时包含X和Y的交易数}{包含X的交易数} ]还是上面的例子100笔订单里20笔包含“牛奶”这20笔中有12笔同时包含“面包”那么{牛奶}→{面包}的置信度就是60%。置信度体现的是“可靠性”。一条规则置信度越高说明X对Y的预测能力越强。但是这里有个历史上多次被踩的坑置信度高不一定代表两者真有强关联有可能Y本身就是高频商品所有人都在买这跟X没什么关系。这就需要第三个指标。提升度Lift提升度在置信度的基础上引入了“基准概率”的概念用来排除Y本身高频带来的干扰[ Lift(X \Rightarrow Y) \frac{Confidence(X \Rightarrow Y)}{Support(Y)} ]公式里除的是Y在全部交易中的支持度相当于一个基准水平。拿上面的数据算一下置信度60%表示买牛奶的人里有60%买了面包假如面包在所有订单中的支持度是60%那么提升度就是60%/60%1提升度等于1说明X和Y相互独立买不买牛奶不影响买面包的概率提升度大于1说明存在正相关X的出现会提升Y的购买概率提升度小于1说明存在负相关X的出现反而抑制了Y的购买所以我在实际项目里看规则第一个先扫Lift值小于1的直接丢等于1的在1附近徘徊的也要小心看待只有明显大于1的规则才有业务落地的潜力。2. Apriori算法原理与执行步骤2.1 Apriori的核心思想Apriori算法是关联规则挖掘的鼻祖1994年被提出来之后直到今天依然是教科书必讲的内容。它的核心思想是一句话一个项集如果是频繁的那它的所有子集也必然是频繁的。这句话反过来说更加有用如果一个项集的子集不是频繁的那这个项集本身也一定不是频繁的。举例说明。{牛奶, 面包, 鸡蛋}总共出现了15次属于频繁项集。那{牛奶, 面包}出现的次数不可能少于15次所以它也是频繁的。反过来如果{啤酒, 白酒}只出现了3次远低于最小支持度阈值那么任何包含{啤酒, 白酒}的超集比如{啤酒, 白酒, 牛奶}只要{啤酒, 白酒}都不达标超集肯定也不达标直接剪掉不用计算。这个性质叫先验性质Apriori Property它最大的价值是大大减少了候选集的数量。如果不加这个剪枝逻辑一个包含N个不同商品的交易库潜在项集数量是2的N次方减1N一过30这个数字就是天文数字根本无法计算。Apriori通过逐层搜索加剪枝的方式把搜索空间压缩到可行范围。2.2 候选集生成与剪枝的组合过程Apriori的完整流程可以拆成三步循环第一步扫描数据库统计所有单品的支持度保留支持度不低于最小支持度阈值的项得到频繁1项集L1。第二步由L1组合生成候选2项集C2。这里有个细节组合不是全排列比如{牛奶, 面包}和{面包, 牛奶}本质上是同一个项集做组合时不区分顺序可以避免重复计算。然后再次扫描数据库统计C2里每个候选的支持度过滤后得到L2。第三步由L2两两组合生成候选3项集C3。组合同样有策略只有当两个频繁2项集的前k-1个元素相同才能组合。比如{牛奶, 面包}和{牛奶, 啤酒}可以组合成{牛奶, 面包, 啤酒}而{牛奶, 面包}和{啤酒, 鸡蛋}不能组合因为前1个元素不相同组合出来的候补子集无法保证有频繁子集。每轮生成候选集之前都要做一遍剪枝检查如果候选项集的任意一个k-1子集不在上一轮频繁集里直接删除候选不用再扫描数据库。这是Apriori性能优化的关键一环。我这里有组简单的示例数据可以走一遍完整流程交易ID购买商品T1牛奶, 面包, 鸡蛋T2面包, 尿布, 啤酒, 鸡蛋T3牛奶, 尿布, 啤酒, 面包T4牛奶, 尿布, 啤酒T5面包, 牛奶, 尿布假设最小支持度计数为2即支持度40%。第一步统计单品频次牛奶4次、面包4次、尿布4次、啤酒3次、鸡蛋2次全部保留为L1。然后生成候选2项集{牛奶, 面包}出现3次{牛奶, 尿布}3次{牛奶, 啤酒}2次{面包, 尿布}3次{面包, 啤酒}2次{面包, 鸡蛋}1次{尿布, 啤酒}3次{尿布, 鸡蛋}1次{啤酒, 鸡蛋}1次。最小支持度计数2过滤后L2得到{牛奶, 面包}、{牛奶, 尿布}、{牛奶, 啤酒}、{面包, 尿布}、{面包, 啤酒}、{尿布, 啤酒}。之后再组合候选3项集剪枝时发现很多组合里有非频繁子集最终只剩{牛奶, 面包, 尿布}计数1次不达阈值。算法到此结束。从这组小数据就可以看出数据规模小的时候Apriori的重复扫描问题不明显但一旦数据量上去反复全表扫描就是硬伤这也是FP-Growth出现的原因。2.3 从频繁项集到强关联规则的生成策略频繁项集找到了不等于规则就有了。规则生成阶段要做的是把每个频繁项集拆成“左侧子集右侧子集”的形式然后逐一计算置信度留下置信度不低于最小置信度阈值的规则。这里有个性能优化点如果某项集是{牛奶, 尿布, 啤酒}可能的规则包括{牛奶}→{尿布, 啤酒}{尿布}→{牛奶, 啤酒}{啤酒}→{牛奶, 尿布}{牛奶, 尿布}→{啤酒}{牛奶, 啤酒}→{尿布}{尿布, 啤酒}→{牛奶}全部枚举出来是2的k次方减2条k是项集大小。但实际业务中右侧含有多个项的规则解释起来比较费劲“买了牛奶就会买尿布和啤酒”还算好理解“买了牛奶和尿布就会买啤酒”也可以接受但如果右侧项再增多规则的应用价值就下降了。所以在实现层面很多工具默认只生成后件为单个项的规则原因不是技术上做不到而是业务解释成本低、落地更容易。还有一点需要注意规则生成阶段同样存在“剪枝”性质如果规则X→Y不满足最小置信度那么X的任何子集作为左侧的规则置信度只会更低还是更高答案是更低。这个方向的单调性跟支持度不太一样原理涉及置信度公式的分子分母变化这里不展开推导实践记住一个结论就行生成规则时可以按后件项数从少到多递增一旦发现某条规则不达阈值和它相关的更大后件规则也直接放弃。3. FP-Growth算法与两种算法的选型对比3.1 FP-Growth是怎么省掉候选集的Apriori有一个绕不开的痛点每一轮都要扫描数据库算支持度候选集一大IO开销直线上升。FP-Growth的思路完全不同它把事务数据库压缩成一颗树所有挖掘都在树上完成全程只扫描两次数据库。这颗树叫FP-Tree频繁模式树。构造过程是这样的第一次扫描数据库统计所有单品的支持度按支持度从高到低排序过滤掉低于阈值的项。第二次扫描数据库逐条读取事务把事务里的商品按第一步排好的顺序重新排列然后从根节点开始逐项插入FP-Tree。树中每个节点都保存商品名和计数凡是共用同一前缀的商品路径就共用节点。举一组简单事务来演示。假设有四条事务按单品支持度排序后的结果是A的频率最大所以排最前面之后是B、C、D、E。第一条事务是A、B、C插入后从根节点分出A(1)A下挂B(1)B下挂C(1)。第二条事务是A、B、DA(1)变成A(2)再走B节点B(2)发现B下没有D节点创建D(1)。第三条事务是A、B、C、E顺着A→B→C路径把A变成A(3)、B(3)、C(2)然后在C下面挂E(1)。第四条事务是B、C根节点下没有B主路径单独新建B(1)→C(1)分支。树建完后所有路径的“节点计数累加和”等于对应项集的总支持度不再需要第三次扫描数据库。FP-Growth的挖掘过程也很有特点它从每个单品节点开始向上收集条件模式基递归构造这颗单品的条件FP-Tree再对条件树继续挖掘直到条件树为空。整个过程不需要枚举所有候选集而是直接在压缩树上做分治挖掘性能上比Apriori高出好几个数量级。3.2 什么时候用Apriori什么时候用FP-Growth两家各有长短不能无脑选FP-Growth。我做项目时一般看两个维度数据规模和实现复杂度。Apriori逻辑简单直观自己写代码也容易调试适合数据集不大、只有几千到几万条记录的情况。而且Apriori在Python生态里有非常成熟的封装mlxtend库几行代码就能跑开发效率高。缺点是数据量一大就力不从心尤其是商品品类多几千个SKU的时候候选集数量膨胀特别快内存和耗时都会失控。FP-Growth则适合大规模数据集速度快、省内存因为全程只扫两遍数据库不需要反复IO。但它的实现复杂度明显更高FP树的构建和维护逻辑比较绕用第三方库的话选择余地又少一些遇到问题不好排查。还有一个折中方案值得提一下当数据量中等又不想引入太重的依赖可以先对数据做一定的“压缩”——比如把商品聚合到品类级别、过滤掉低频长尾商品再用Apriori跑。实际项目里这些预处理往往比换算法更能解决性能问题。我把两个算法的优劣总结成一张对比表对比维度AprioriFP-Growth核心思路候选项集逐层搜索 剪枝事务压缩成树 递归挖掘数据库扫描次数每轮都要全表扫描仅扫描两次候选集生成需要生成大量候选集不需要候选集时间复杂度高数据量敏感低适合大规模数据实现复杂度简单易于理解复杂树结构较绕生态支持Python生态成熟库较少部署成本高适用场景中小数据集、教学演示大规模数据集、生产环境4. 用Python完成关联规则全流程演示4.1 模拟一份购物篮订单数据这一节我用Python带大家完整跑一遍关联规则分析。用到的主要库是pandas、mlxtend和该库底层的transaction编码器。先说环境在终端里执行pip install pandas mlxtendmlxtend这个库大家可能不太熟它是一个机器学习扩展库里面封装了Apriori和关联规则生成函数做这种分析很方便。数据我这边用代码模拟一份模拟一个社区超市的销售订单大概一千笔左右商品种类控制在十几种方便观察结果import pandas as pd import random random.seed(42) # 商品池 items [牛奶, 面包, 鸡蛋, 尿布, 啤酒, 薯片, 可乐, 苹果, 香蕉, 面条, 酱油, 酸奶, 饼干, 纸巾, 洗衣液] # 模拟1000笔订单每笔订单包含3-8种商品 transactions [] for _ in range(1000): k random.randint(3, 8) txn tuple(random.sample(items, k)) transactions.append(txn) print(f共 {len(transactions)} 笔订单)随机生成数据的好处是跑出来的结果足够典型坏处是没什么真实业务逻辑在里面所以这里只是演示流程真实的购物篮数据需要从数据仓库取数处理。4.2 数据形状转换与频繁项集挖掘关联规则要求的数据格式是“每一行是一笔订单每一列是一个商品值为是否购买”。这种格式也叫one-hot事务编码。直接把原始订单列表丢给mlxtend不行需要先转换from mlxtend.preprocessing import TransactionEncoder from mlxtend.frequent_patterns import apriori encoder TransactionEncoder() one_hot encoder.fit(transactions).transform(transactions) df pd.DataFrame(one_hot, columnsencoder.columns_) print(df.head()) print(df.shape)转换后的表格大概长这样第一列是“牛奶”是否购买第二列“面包”是否购买以此类推每个格子要么是True要么是False。接下来设最小支持度阈值。这里不能拍脑袋选先看一下单品的平均支持度support_series df.mean().sort_values(ascendingFalse) print(support_series)我的建议是如果目标是找“有业务可操作性的关联”最小支持度设在1%到5%之间比较常见。设高了只剩那些本来就最畅销的单品在互相组合形同废话设低了挖掘出来的项集很多都是低频长尾不具备普遍性。这份模拟数据单品支持度普遍在30%上下波动我把min_support设为0.1保证结果不至于太稀疏。frequent_itemsets apriori(df, min_support0.1, use_colnamesTrue) frequent_itemsets.sort_values(bysupport, ascendingFalse).head(10)输出结果里会显示每一行的itemsets比如{牛奶, 面包}和support值比如0.231。这表示有23.1%的订单同时包含牛奶和面包。4.3 生成关联规则并按业务价值筛选频繁项集只是“共现清单”要变成“如果买A则买B”的规则还需要用association_rules函数from mlxtend.frequent_patterns import association_rules rules association_rules(frequent_itemsets, metriclift, min_threshold1.0) rules rules[[antecedents, consequents, support, confidence, lift]] rules.sort_values(bylift, ascendingFalse).head(10)metric和min_threshold这对参数划了一条规则筛选的底线我用的是“提升度不低于1”表示只要正相关的规则。有些项目还会要求置信度也设下限比如confidence0.5这取决于业务方能不能接受“看了左侧推荐右侧只有一半人会买”的效果。生成后的规则DataFrame里antecedents是前件项集consequents是后件项集。排序后提升度最高的几条规则往往是低频但强关联的组合比如“{酱油}→{面条}”这种意味着买酱油的顾客里买面条的比例远超总体面条购买率。从业务角度这就是捆绑推荐的机会在酱油货架旁放面条试吃装。跑完流程我建议做一步业务侧筛选。关联规则跑出来上百条很常见但真正有价值的就前面那几条。我的筛选标准是三步走第一步过滤lift小于1.2的规则小于这个数说明正关联不显著第二步过滤support太低的规则比如低于0.02覆盖面不够第三步过滤左侧或右侧只有单一商品的规则这类最容易在报表里解释也方便运营执行5. 关联规则实战中的常见问题与调参经验5.1 频繁项集为空或规则过少是怎么回事这是最常遇到的问题之一。我见过不少人拿到数据直接默认参数跑结果频繁项集结果表一大半是空的或者规则数只有个位数。原因通常是min_support设得太高。不同数据集的销售密度完全不一样。超市生鲜这类高频消费品单品支持度普遍较高阈值设在5%都合理但如果是汽车配件这类长尾行业单个零件的购买率可能就是千分之几你阈值设在5%所有项集都会被过滤光当然跑不出东西。我的做法是动手跑之前先算一下所有单品的支持度分布看看中位数和分位数是多少。然后从比中位数略低的值开始试如果频繁项集数量太多再逐步往上调。说到底参数是个经验活但“先看分布、再定阈值”这个方法论是通用的。5.2 规则数量爆炸怎么压缩如果一场分析跑出几千条规则大概率是min_support和min_confidence都设得太低了。支持度低会让大量低频随机共现进入候选视野置信度低会让这些凑数的共现轻松变成规则。压缩规则有几个实用方向第一个方向是提高置信度门槛。把confidence限定在0.5或0.6以上能过滤掉大量偶然共现。第二个方向是提高lift门槛。保守情况下要求lift至少大于1.2严格一点1.5以上保证挖掘出来的是“有业务增量”的规则。第三个方向是业务维度的过滤同一品类内部商品的关联比如纸巾和抽纸业务价值往往不如跨品类关联可以直接删掉。第四个方向是合并相似规则比如{黄油}→{面包}和{黄油, 果酱}→{面包}后者的支持度肯定更低置信度可能更高但实际落地的思路是一样的留一条表达最清晰的即可。5.3 置信度高但提升度也高是否一定值得做业务不一定。真实业务场景里高置信度高提升度只能说明统计层面的强相关性但因果关系可能完全说不通。举个例子某个促销活动期间A商品做活动的顾客大概率都额外买了架上的B赠品统计出来A和B的关联很强但活动结束这个关联就消失了。这就是我前面说的关联规则挖掘的本质是发现相关性不是证明因果性。业务方拿规则去落地之前一定要加一重业务判断这个关联背后是否有合理的购物场景解释说不出合理解释的规则宁可不用。5.4 数据预处理的几个隐蔽坑最后说说那些“不踩一次根本不知道”的坑。坑一同一顾客在同一天多次购买的订单要不要合并。一个顾客买了牛奶半小时后又进来买了面包统计上是两笔订单关联规则会认为“牛奶和面包没有共现”但实际这是一次完整的购物行为。解决方案是交易数据的聚合粒度要提前想好按“顾客日期”合并成一次购物篮而不是直接按流水号来算。坑二缺失值不能直接忽略。有些系统导出的订单明细里商品字段有空值如果当成独立商品或者直接丢弃都会影响支持度统计。正确做法是清洗时空值行直接删掉或者至少确认占比不高后再删。坑三商品编码粒度不统一。同样的商品有的门店用单品条码有的用销售汇总码混在一起计算会把同一个商品拆成两个关联关系就被稀释了。跑之前需要把编码对齐到统一层级。6. 从结果到业务落地的关联规则应用思路6.1 关联规则与推荐系统结合关联规则在推荐场景里最直接的应用就是“购买过A的顾客顺便推B”。和基于协同过滤的推荐相比关联规则有一个很明显的优势它不依赖用户历史行为序列的丰富程度。新用户、低活跃用户没有足够的行为数据协同过滤基本抓瞎但关联规则只要知道该用户当前正在购买或浏览的商品就可以立刻给出可解释的推荐候选项。在实际系统里关联规则通常是作为一个召回通道存在用户把某商品加入购物车后端立即用高频关联规则查询合适的搭配商品作为购物车推荐或者结算页加购引导。这个通道计算代价小、响应快而且由于规则是人类可读的运营人员可以直接在后台手工增删规则避免黑盒不可控的问题。6.2 捆绑促销与货架陈列传统的捆绑促销设计一般靠商品经理的经验判断但关联规则可以给这个经验判断补上数据支撑。比如分析发现{洗发水}→{护发素}的提升度高达3.5而且支持度也足够大那么做洗发水促销的同时把护发素以搭售折扣形式打包上架就比盲目满减更精准。货架陈列也是个经典落点。实体门店里高频强关联的商品如果摆放位置相隔太远顾客往往只买其中一个白白损失销售额。把这些统计出来的关联对按提升度排序再结合门店动线图调整陈列位置是可以直接看见销售变化的运营动作。我见过一个做日化零售的案例把关联最强的三组商品调整到相邻货架后捆绑购买率提升了十几个百分点这就是关联规则在实体渠道里的价值。6.3 频繁项集用于品类管理和异常检测除了关联规则本身挖掘出来的频繁项集还可以反推品类结构。比如某连锁超市发现{香醋}经常不跟{酱油}出现在同一购物篮里但和{饺子皮}关联很强这说明这些门店里香醋的核心消费场景不是中餐炒菜而是饺子蘸料。基于这个发现补货比例和陈列位置都可以做相应调整。异常检测方向更有意思。如果某个时间段内原本稳定的高频项集突然消失或者出现了平时极少见的项集组合往往意味着有异常因素在起作用比如系统数据故障、某门店盘点差异、某个品类的临时缺货。维护一套“正常状态的频繁项集基线”再周期性对比当前周期也是一种便宜又高效的业务监控手段。6.4 关联规则分析结果的可视化呈现结果出来以后最忌讳的就是丢一张几百行的规则表给业务方。我一般会做两张图第一张是频繁项集的词云或者热度矩阵。把商品两两组合的支持度展示成一个三角热力矩阵哪对商品关联强看一眼颜色深浅就清楚比翻Excel高效太多。第二张是规则的网络图。把商品之间的关系画成节点和连线连线的粗细代表支持度颜色深浅代表提升度。这张图的好处是能一眼看出哪些商品是整个网络的枢纽它们的关联价值往往被低估值得重点做运营。Python里做第一张图用matplotlib的imshow就行做第二张图可以用networkx画力导向图。代码不算复杂但表达效果比纯数字好得多强烈建议在项目汇报里用上。在真实项目里调参这件事我的体会是第一次跑通永远比一次跑准重要。先把流程跑起来看到输出结果的存在感再根据结果反推参数该往哪个方向调这是最务实的路径。关联规则算法的应用深度其实不在算法本身而在怎么把统计发现翻译成业务动作。你跑出一条高提升度规则能说清楚它背后的购物场景是什么能想明白它在货架、页面或者推荐位上具体怎么用这才算是真正把这套算法落到了地上。