ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python关联分析:从Apriori到规则筛选,找出真正可落地的强关联规则

Python关联分析:从Apriori到规则筛选,找出真正可落地的强关联规则 1. 先回答一个扎心的问题跑完apriori你真敢用那些规则吗前段时间帮一个做零售数据的朋友看项目他兴冲冲地跑了一版Python关联分析把经典的apriori算法套在门店半年的销售流水上出了几百条频繁项集和关联规则。朋友圈里晒出来的热力图很好看可当我问他这些规则里你准备落地哪几条、怎么落地时他愣住了。这大概是我见过最普遍的现象——频繁项集和关联规则在Python里跑出来很容易但哪些规则真正值得用这个问题才是整个项目里最容易被跳过的关键环节。这不是技术门槛的问题而是评价体系的问题。很多人对关联分析的认知停留在啤酒和尿布的故事上觉得只要支持度和置信度跑过阈值就能拿到一条可落地的策略。但实际跑过几轮真实数据之后你会发现高置信度规则里充斥着一堆废话比如买牛奶的人也会买面包这种规则放在业务里既没法指导选品也没法做捆绑促销因为它反映的只是两个高频商品恰好经常同时出现并没有给你任何额外的决策增量。这篇文章我想从一个完整项目验收的角度聊聊Python关联分析这件事从频繁项集的挖掘到关联规则的生成再到规则价值的评估和筛选。重点放在后面两个环节也就是哪些规则真正值得用。文章里会用一组可以手算的小样本数据贯穿始终方便你把每一步的数学逻辑对照着代码看明白。同时会给出mlxtend库的完整实操代码以及我在真实项目里踩过的坑。适合正在做销售数据、用户行为日志、内容推荐标签分析的同学也适合刚开始接触数据挖掘、想知道apriori到底在算什么的新手。2. 频繁项集从什么经常一起出现到apriori剪枝原理2.1 先搞清楚频繁项集到底在算什么关联分析的输入通常是一组事务数据每一行是一次交易、一次会话、或者一条日志每一事务里包含若干个项目。比如超市里一个订单就对应一条事务订单里的每个商品就是一个项目。关联分析要回答的问题是哪些项目组合在事务里经常一起出现而且出现的频率高到不像偶然。这个经常一起出现在数学上就叫支持度。某个项集的支持度就是包含该项集的事务数除以总事务数。比如表1这组模拟的超市小票数据共5条事务事务ID购买商品T1牛奶, 面包, 尿布T2牛奶, 面包T3牛奶, 尿布, 啤酒T4面包, 尿布, 啤酒T5牛奶, 面包, 尿布, 啤酒计算项集{牛奶, 面包}的支持度它出现在T1、T2、T5这三条事务里所以support({牛奶,面包}) 3/5 0.6。如果事先设定一个最小支持度阈值比如min_support0.4那么所有支持度≥0.4的项集就叫频繁项集。在上面的数据里{牛奶}、{面包}、{尿布}、{啤酒}、{牛奶,面包}、{牛奶,尿布}、{面包,尿布}、{尿布,啤酒}、{牛奶,面包,尿布}、{牛奶,尿布,啤酒}、{面包,尿布,啤酒}这些都是频繁项集。2.2 apriori的剪枝思想为什么不用穷举所有组合如果有几十上百个不重复商品组合数会爆炸。假设有100个商品光大小为3的项集就有100×99×98/6约16万个更别说更大尺寸的项集。apriori算法最核心的贡献是一条先验原理如果一个项集是非频繁的那么它的所有超集也一定是非频繁的。这个逻辑很好理解。{牛奶,面包}的支持度是0.6它只会低于等于{牛奶}和{面包}各自的支持度因为一个项集要同时包含更多项目能命中它的事务只会更少不会更多。反过来如果{啤酒,红酒}的支持度只有0.1那{啤酒,红酒,奶酪}的支持度无论如何不可能超过0.1所以在扩展候选项集的时候这些注定没戏的组合可以直接剪掉不用白费算力。用Python实现apriori最常用的库是mlxtend。它的调用方式非常简洁后面会给出完整代码。这里想强调的是理解剪枝原理能帮你规避一个常见的调参误区不要为了多挖出一些规则把min_support压得特别低。在真实数据集上min_support如果低于0.01频繁项集数量会呈指数级上涨很多出现在几十条事务里的三四项集都会被捞出来但它们对业务来说基本就是噪声。频繁项集的数量级突增往往不是因为找到了宝藏而是因为阈值放得太松。2.3 Python里两套主流实现怎么选做频繁项集挖掘时我一般会根据数据量级在mlxtend和efficient-apriori之间选择。mlxtend的frequent_patterns.apriori功能完整配合association_rules可以一站式生成规则适合中小规模数据而且返回的结果是DataFrame后面做条件筛选非常方便。efficient-apriori用了一种更紧凑的内部存储策略在数据量大、项目数多的时候运行更快也能直接返回规则对象。如果你发现apriori在大数据量下慢得离谱可以试试用mlxtend.frequent_patterns.fpgrowth它是FP-Growth算法的实现不需要反复扫描数据库生成候选集速度通常比apriori快一个量级。我的经验是平时做探索性分析、几千到几万条事务直接用mlxtend的apriori就够了跑全量数据或项目数超过几万个可以换fpgrowthAPI几乎一样迁移成本很低。3. 置信度、提升度与那些看着很强其实鸡肋的规则3.1 从频繁项集到关联规则置信度的条件概率错觉拿到频繁项集之后下一步是生成关联规则。一条规则写成A→B的形式表示购买A的情况下有多大倾向购买B。这里唯一的关键指标是置信度公式是confidence(A→B) support(A∪B) / support(A)。用上面的例子{牛奶}→{面包}的置信度 0.6 / 0.8 0.75。翻译成人话在所有买了牛奶的人里75%的人同时买了面包。到这里很多人就开始下结论了这条规则置信度0.75很高可以做捆绑促销。但实际项目里这就是最大的认知陷阱。置信度只描述了条件概率这一个侧面它完全没有考虑B本身在全部事务里有多常见。如果面包本身就是热销品80%的顾客都会买面包那么买牛奶的人75%买面包甚至比不买牛奶的人反而买面包的比例更低。换句话说牛奶和面包其实可能存在某种程度的竞争关系而不是协同关系。3.2 提升度帮你打破条件概率错觉为了修正置信度不看基线的问题关联分析引入提升度lift(A→B) confidence(A→B) / support(B)。这个指标衡量的是已知A之后B发生的概率相对B自然发生的概率放大了多少倍。拿{牛奶}→{面包}继续算confidence 0.75support(面包) 4/5 0.8lift 0.75 / 0.8 0.9375。这个数值小于1说明买牛奶实际上轻微降低了买面包的概率这条规则虽然置信度很高但对业务来说不但没有正向价值还可能是反向的。再看{尿布}→{啤酒}这条规则confidence 3/4 0.75support(啤酒) 3/5 0.6lift 0.75 / 0.6 1.25。提升度大于1说明尿布和啤酒之间存在正向关联买尿布的人更可能买啤酒这个结论是站得住的。关于lift的解读有一条很实用的经验线lift 1表示正向关联lift 1表示两个事件独立lift 1表示负向关联。实际项目里我会要求候选规则lift至少大于1.1否则即使置信度很高也说明不了什么增量价值。千万不要只盯着置信度看那样你筛出来的规则大概率是高频商品互相捆绑的伪规律。3.3 手算一遍建立三个指标的联动关系为了让你更直观地感受支持度、置信度、提升度三者之间的关系我们把手上的小样本数据算成一张规则表。下面只保留置信度≥0.5的几条常见规则规则支持度置信度提升度牛奶→面包0.600.750.94牛奶→尿布0.600.750.94尿布→啤酒0.600.751.25面包→牛奶0.600.750.94啤酒→尿布0.601.001.25尿布→牛奶0.600.750.94牛奶→面包,尿布0.400.501.04你注意看规则牛奶→面包和尿布→啤酒置信度完全相同都是0.75但提升度一个小于1一个大于1。如果只看置信度这两条规则会被当成同一档次的发现可一旦代入提升度价值立刻分出了高下。这就是后文筛选规则时需要用多指标而不是单一指标的原因。4. 真正值得用的规则引入leverage、conviction与组合筛选策略4.1 提升度什么时候会失灵提升度虽然比置信度靠谱但它在两类场景下依然会骗人。第一类是低频项上的高lift。如果一个项集的支持度特别低例如0.005但它的lift可能高达3甚至5因为分母support(B)很小随便一点共现都会被放大。这类规则在成千上万条规则里最容易吸引眼球但落地时你会发现它覆盖的样本太少根本撑不起一个促销活动的选品逻辑。第二类是中低频项但带强烈季节性的数据比如年底的牛奶和灯笼看起来提升度很高但放到全年视角下就只是一个季节性巧合。所以我不建议把某一项指标作为唯一筛选依据。比较成熟的做法是组合指标一起看这也是当前主流的学术和应用共识。4.2 三个互补指标的计算逻辑leverage、conviction、zhangs_metric在mlxtend生成规则时association_rules函数会顺带计算出好几个评估指标其中三个最大用途是**Leverage杠杆率**的公式是leverage(A→B) support(A∪B) - support(A) × support(B)。它衡量的是实际共现概率与假设完全独立时共现概率的差值。差值为正表示正相关为0表示独立为负表示负相关。和lift相比它不受support(B)太小的影响是一个在频率尺度上直观的差值指标。**Conviction确信度**的公式是conviction(A→B) (1 - support(B)) / (1 - confidence(A→B))。它想表达的是如果没有AB出现会困难多少倍。这个指标官方解释有点绕你可以这样理解它衡量的是在置信度不够理想的情况下B被A带出来的额外保证程度。conviction越大说明A对B的带动作用越强且不像lift那样对低频项敏感。**Zhangs metric张氏度量**是一个综合了support、confidence和lift的规范化指标取值范围在-1到1之间越接近1说明正向关联越强越接近-1说明负向关联越强。它在处理强负相关时比lift和conviction都要稳定。4.3 一个可以直接抄作业的四象限筛选法根据我在项目里的经验建议把规则按业务扩张潜力和统计可信度拆成两个维度来筛选。统计可信度看支持度、置信度和p值类信息业务扩张潜力看lift、leverage和商品本身的利润结构。落到操作层面我会定这样一组默认阈值指标筛选区间原因support≥ 0.02 且 ≤ 0.6太小没有覆盖力太大说明是高频商品自然共现confidence≥ 0.5低于0.5说明规则本身没有明显方向性lift≥ 1.2至少要带来20%以上的概率增益leverage≥ 0.01确保不是低频项上的虚高conviction≥ 1.2保证规则有拉动意义不是简单伴生再把满足这些条件的规则按业务场景归类一类是高lift、高leverage、高confidience的强正向规则适合做捆绑促销、组合推荐一类是高support、lift接近1的中性规则适合做备选项但不要花太多运营资源还有一类是lift明显大于1但support非常低的长尾规则这种适合做个性化推荐里的补充不适合做全量活动。4.4 警惕规则数量爆炸加一个规则长度约束还有一个很实际的问题频繁项集一旦挖到4项、5项生成的规则里会有大量前件太长的规则。比如{A,B,C}→{D}这种规则在数据里可能只有几笔支持置信度再高也不具备业务解释性。我通常在筛选时直接加一条过滤条件规则两侧的项目数分别不超过2个总长度不超过3个。几乎每次这么做以后候选规则表都会大幅收缩剩下的规则才真正敢拿去给人看。5. 完整实操mlxtend从原始订单到规则落地的全套流程5.1 环境准备与数据结构化把订单表转成one-hot事务矩阵先说环境。除了基础的pandas、numpy之外需要安装mlxtend。如果你的Python环境里还没有这个包命令行执行一下即可pip install mlxtend关联分析输入的数据结构比较讲究。mlxtend原生的apriori接口需要的是one-hot编码的事务矩阵每一行是一条事务每一列是一个项目单元格用True或False标记该事务是否包含该项目。假设你的原始数据是两张表订单表和订单明细表最省事的转换逻辑是先把明细按订单聚合为list再用TransactionEncoder转成矩阵。import pandas as pd from mlxtend.preprocessing import TransactionEncoder # 模拟原始订单明细 orders [ [牛奶, 面包, 尿布], [牛奶, 面包], [牛奶, 尿布, 啤酒], [面包, 尿布, 啤酒], [牛奶, 面包, 尿布, 啤酒], ] te TransactionEncoder() te_ary te.fit_transform(orders) df pd.DataFrame(te_ary, columnste.columns_) print(df)输出结果长这样牛奶面包尿布啤酒TrueTrueTrueFalseTrueTrueFalseFalseTrueFalseTrueTrueFalseTrueTrueTrueTrueTrueTrueTrue这是所有后续步骤的数据基础。我在做真实项目时最常处理的坑订单表里重复购买的商品没去重导致同一张订单里同一个商品出现两行。建议在聚合前先对订单明细执行drop_duplicates()否则one-hot矩阵里同一商品在一条事务里只会保留一次而重复计数会影响支持度计算。5.2 频繁项集挖掘用apriori还是fpgrowth数据转好后挖掘频繁项集就一行代码from mlxtend.frequent_patterns import apriori, fpgrowth # 用apriori挖掘频繁项集min_support0.4 frequent_itemsets apriori(df, min_support0.4, use_colnamesTrue) # 如果数据量大可以换成fpgrowth函数签名几乎一样 # frequent_itemsets fpgrowth(df, min_support0.4, use_colnamesTrue) print(frequent_itemsets)use_colnamesTrue的意思是项集列直接显示商品名而不是列索引调试时非常直观。apriori和fpgrowth的返回值都是DataFrame包含itemsets和support两列。注意min_support的设置要结合数据规模。我的习惯是先用0.05试跑看返回的频繁项集行数如果超过几千行就上调如果只有十几行就下调到0.02。频繁项集行数控制在100到1000行之间比较适合继续做规则分析太少了说明没有挖掘空间太多了后续规则筛选会非常耗内存。5.3 生成关联规则并写一个自动筛选函数生成规则用association_rules它在mlxtend.frequent_patterns里from mlxtend.frequent_patterns import association_rules rules association_rules(frequent_itemsets, metriclift, min_threshold1.0) print(rules.columns)这里metric和min_threshold是生成阶段的一个预筛。metriclift, min_threshold1.0表示只保留lift≥1.0的规则基础框架生成后再用前面的多指标组合精确过滤。rules这个DataFrame里每一行是一条规则列包含antecedents、consequents、antecedent support、consequent support、support、confidence、lift、leverage、conviction、zhangs_metric。它已经帮我们把评估指标全部算好了下面的工作就是看怎么选。我通常会把筛选逻辑封装成一个函数方便不同数据集复用def select_actionable_rules(rules, min_support0.02, min_confidence0.5, min_lift1.2, min_leverage0.01, min_conviction1.2, max_items3): filtered rules[ (rules[support] min_support) (rules[confidence] min_confidence) (rules[lift] min_lift) (rules[leverage] min_leverage) (rules[conviction] min_conviction) (rules[antecedents].apply(len) rules[consequents].apply(len) max_items) ] return filtered.sort_values(lift, ascendingFalse) actionable_rules select_actionable_rules(rules)这个函数实现了上面说的多指标联合筛选加上规则总长度不超过3个项目的约束。几个阈值可以根据项目数据量调整样本总量只有几百的事务support阈值可以放宽一点但lift和conviction这种比值类指标不要轻易放宽因为它们是你判断规则是否有增量价值的核心防线。筛选之后最好把规则导出成Excel或CSV做进一步人工排序。我一般会额外计算一列提升度×置信度作为综合评分列再按业务毛利排序把高分且高毛利的规则优先交给运营同事验证。actionable_rules actionable_rules.copy() actionable_rules[score] actionable_rules[lift] * actionable_rules[confidence] actionable_rules.to_csv(candidate_rules.csv, indexFalse)6. 那些文档里不会写的东西我踩过的坑和几条原则6.1 时间顺序是个隐形的坑关联规则不等同于先买A再买B很多人在做用户行为时序数据时会把用户在一个月内的全部点击、收藏、购买记录做成一条事务然后跑关联分析得出访问了A页面的人会访问B页面。但仔细想想关联规则公式里压根没有时间顺序support和confidence都只统计是否在同一事务里出现过。如果A和B的先后顺序对你的业务结论有影响就必须在数据准备阶段把同一用户的行为按时间窗口切分比如2小时内算一个会话而不是按自然月聚合。否则你得到的规则很可能把先看A后看B和先看B后看A混为一谈业务上根本没法落地。6.2 高lift的低频规则看起来很美落地就赔钱这是我在促销选品项目里踩过最深的坑。那次的规则表里出现了一条lift高达4.2的规则某款低度酒→一款进口零食。当时运营同事很兴奋准备做一个组合上新活动。我一查支持度才发现这条规则只覆盖了全量订单的0.3%也就是一周才几单。真要围绕它做捆绑推荐曝光量小不说还可能因为样本太少产生误判。后来我养成了一个习惯在给运营的可执行规则清单里永远分两栏一栏是高覆盖主推组合一栏是高增益长尾组合两类规则用不同的运营策略。高覆盖组合做全站推荐高增益组合只在相关商品详情页做个性化推荐。6.3 相关不等于因果这是关联分析永远解释不了的事关于哪些规则真正值得用我自己的体会是关联分析能给你的是值得做实验的候选清单而不是可以直接执行的商业结论。比如冰淇淋销量和溺水人数在所有统计上都是强相关但没有人会认为卖冰淇淋能提高安全性。你筛出来一条买纸尿裤的人更倾向买啤酒的规则它背后的原因可能是年轻爸爸群体下班后顺便买酒这个洞察可以用来指导广告定向但它本身不是因果关系。所以在交付结果时我通常会在报告最后加一段话这些规则需要A/B测试验证或者至少抽样电话回访验证再决定是否全量上线。6.4 最后的实操建议规则是用来迭代的不是一次定死的关联分析不是一锤子买卖。数据会更新用户偏好会漂移今天算出来的一条高lift规则三个月后可能因为季节变化、供应链调整、竞品上新而完全失效。我建议把频繁项集和关联规则的脚本做成定期任务至少每个月重跑一次并且把历史版本的规则存档做对比。当某条曾经很稳定的规则出现lift明显下降时往往预示用户消费行为在发生变化这信息本身比规则还有价值。回到开头那个朋友的项目最后我帮他把筛选逻辑落地成了一套固定流程min_support0.02、confidence0.5、lift1.2为底线再结合leverage和conviction做二次过滤规则数量从最初的几百条收敛到二十几条。交给运营的候选清单里每一行都标注了支持的样本量、可能的业务含义和对应的人群建议。这次他总算没有再看着几百条规则发愁了。关联分析这个工具就像一把筛子筛出来的东西能不能吃不能光看筛子转得快不快还得看筛网孔径合不合适更要看你到底想筛出什么。把哪些规则真正值得用想清楚你这一整套Python关联分析的功夫才算真正落地。
返回列表