
简介一套Python频繁模式挖掘实践代码包面向数据挖掘初学者、数据分析师及算法课程项目开发者解决从交易数据中发现频繁项集与关联规则的落地实现问题。代码包共2个文件均为Python脚本体积仅4KB涵盖基础演示版与完整流程版两种实现包含数据预处理、频繁项集搜索、支持度与置信度计算、关联规则生成等功能模块结构紧凑且便于二次修改。目前已有262人学习下载可当作算法入门与课程设计的参考案例。运行代码可直观看到频繁项集筛选过程及Apriori算法的迭代逻辑同时输出关联规则的可视化图表帮助使用者理解不同支持度阈值对结果的影响。代码注释简洁算法流程清晰支持直接替换数据集运行并保存规则结果适用于市场篮子分析、日志行为挖掘等常见场景是一份兼顾原理与实现、可直接用于课程实验的轻量级参考资料适合在Jupyter Notebook或PyCharm等环境中直接运行。1. 先搞清楚频繁模式挖掘到底在挖什么做数据分析或者偶尔碰电商数据的同学一定绕不过“频繁模式挖掘”这个名字。它还有个更接地气的说法叫“购物篮分析”——你去超市买了一袋面包、一盒牛奶、一串香蕉收银小票上这些商品共同出现就是一种模式如果成千上万张小票里“面包牛奶”反复同时出现那这就是一个有商业价值的频繁模式。应用上最常见的例子就是啤酒和尿布的故事把啤酒放在尿布旁边销量悄悄涨了一截。背后的原理就是我们今天要跑的这段代码。频繁模式挖掘的核心目标就两个一是找出“哪些东西经常一起出现”二是从这些组合中提炼出“如果买了A有多大可能买B”之类的关联规则。前者叫频繁项集挖掘后者叫关联规则挖掘。本文给出的完整代码覆盖了从数据准备、算法实现到结果可视化的全部流程运行之后会生成频繁项集表、关联规则表和两张结果图片适合正在学数据挖掘、准备做毕业论文实验或者工作中需要做商品捆绑推荐的读者直接“抄作业”。算法选择上我用了两个经典方案Apriori 和 FP-Growth。Apriori 逻辑简单适合理解原理FP-Growth 不生成候选集数据量大时性能好很多。完整代码里两个都写了跑一遍对比比单纯看理论舒服得多。对了依赖库我选了mlxtend它把频繁项集挖掘和关联规则计算封装得很好不需要自己从零实现 Apriori 的逐层迭代。2. 完整可运行的代码从数据集到频繁项集2.1 环境准备和三行安装命令写代码之前先把环境准备好。我这里用的 Python 3.10理论上 3.8 以上都不会有问题。核心依赖就三个pandas、mlxtend、matplotlib画网络图还需要networkx。安装命令直接复制pip install pandas mlxtend matplotlib networkx如果你用的是 Anaconda也可以用conda install -c conda-forge mlxtend。pandas负责处理数据mlxtend负责 Apriori、FP-Growth 和关联规则计算matplotlib和networkx负责画图。这几个库都是数据挖掘的常客装好之后基本不用再补别的。2.2 数据准备事务数据长什么样频繁模式挖掘的输入数据有两种常见形态。第一种是“事务列表”也就是一行一次购买记录每行是顾客买的商品集合第二种是“one-hot 编码表”每一行是一个事务每一列是一个商品买了就填 1没买就填 0。mlxtend里的apriori和fpgrowth函数默认要求输入第二种形态所以我们需要做个转换。我这里就直接用一个小型超市模拟数据写死在脚本里方便你复制运行。import pandas as pd from mlxtend.preprocessing import TransactionEncoder from mlxtend.frequent_patterns import apriori, fpgrowth, association_rules # 构造事务数据每一行代表一次购物记录 dataset [ [牛奶, 面包, 黄油], [牛奶, 面包, 鸡蛋], [牛奶, 啤酒, 尿布], [面包, 黄油, 饼干], [牛奶, 面包, 黄油, 啤酒], [面包, 啤酒, 尿布], [牛奶, 尿布, 啤酒, 鸡蛋], [面包, 牛奶, 黄油, 鸡蛋], [啤酒, 尿布], [牛奶, 面包, 啤酒, 尿布, 鸡蛋], ] # 将事务数据转换为 one-hot 编码的 DataFrame te TransactionEncoder() te_ary te.fit_transform(dataset) df pd.DataFrame(te_ary, columnste.columns_) print(转换后的事务表前5行) print(df.head())这段代码的核心在TransactionEncoder。很多初学者第一次跑apriori时报错报错信息大概是“Expecting pandas DataFrame with 0/1 values”原因就是直接传了一个普通二维列表进去。TransactionEncoder会自动扫描所有事务中出现的商品生成列名然后填充 0/1省去手动构造稀疏矩阵的麻烦。2.3 Apriori 挖掘核心代码数据准备好之后挖掘频繁项集只需要一行函数调用。min_support是最小支持度意思是某个商品组合至少出现在多少比例的事务中use_colnamesTrue表示返回商品名而不是列索引。# 使用 Apriori 挖掘频繁项集 frequent_itemsets_ap apriori( df, min_support0.3, # 最小支持度 30% use_colnamesTrue, max_lenNone # 不限制项集内商品数量 ) # 按支持度降序排列方便观察 frequent_itemsets_ap frequent_itemsets_ap.sort_values(support, ascendingFalse) print(\nApriori 频繁项集支持度 0.3) print(frequent_itemsets_ap) # 基于频繁项集生成关联规则 rules_ap association_rules( frequent_itemsets_ap, metricconfidence, # 按置信度评估规则强度 min_threshold0.5 # 最小置信度 50% ) # 按提升度降序排列 rules_ap rules_ap.sort_values(lift, ascendingFalse) print(\nApriori 关联规则置信度 0.5) print(rules_ap[[antecedents, consequents, support, confidence, lift]])跑完之后会得到一张频繁项集表里面会出现类似(牛奶, 面包)这样的组合。以我这份数据为例牛奶和面包同时出现在 7 个事务里支持度 0.7说明二者关联极强。关联规则表里(牛奶) - (面包)这条规则的置信度是 0.875提升度约 1.25说明“买牛奶的人买面包的概率”是“随机购买面包概率”的 1.25 倍。2.4 FP-Growth 对比实现FP-Growth 的代码跟 Apriori 几乎一模一样只是函数名换成了fpgrowth。这也是mlxtend设计得比较好的地方算法可以无缝替换。# 使用 FP-Growth 挖掘频繁项集 frequent_itemsets_fp fpgrowth( df, min_support0.3, use_colnamesTrue ) frequent_itemsets_fp frequent_itemsets_fp.sort_values(support, ascendingFalse) print(\nFP-Growth 频繁项集支持度 0.3) print(frequent_itemsets_fp) # 基于 FP-Growth 结果生成关联规则 rules_fp association_rules( frequent_itemsets_fp, metricconfidence, min_threshold0.5 ) rules_fp rules_fp.sort_values(lift, ascendingFalse) print(\nFP-Growth 关联规则置信度 0.5) print(rules_fp[[antecedents, consequents, support, confidence, lift]])我在实际测试中发现小数据集上 Apriori 和 FP-Growth 的结果完全一致毕竟它们挖的是同一个频繁项集。区别体现在数据量上当你有几十万条事务、上千种商品时Apriori 需要反复扫描数据和生成候选集速度会肉眼可见地变慢FP-Growth 把事务压缩到一棵 FP-Tree 里只需要扫描两遍原始数据性能优势非常明显。所以如果你跑大规模数据优先用fpgrowth。3. 结果图片怎么画支持度-置信度散点图与规则网络图3.1 散点图一眼看出规则取舍生成结果之后如果只是打印一堆表格数字说服力不够图表才是给人看的。我一般会画两张图第一张是“支持度-置信度-提升度”三维散点图横轴是支持度纵轴是置信度点的颜色深浅或大小表示提升度。import matplotlib.pyplot as plt # 配置中文字体否则会出现方块乱码 plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False plt.figure(figsize(10, 6)) scatter plt.scatter( rules_ap[support], rules_ap[confidence], crules_ap[lift], cmapviridis, srules_ap[lift] * 80, alpha0.6, edgecolorsw, linewidth0.5 ) plt.colorbar(scatter, label提升度 (lift)) plt.xlabel(支持度 (support)) plt.ylabel(置信度 (confidence)) plt.title(关联规则分布支持度-置信度-提升度) plt.grid(True, linestyle--, alpha0.4) plt.tight_layout() plt.savefig(关联规则散点图.png, dpi150) plt.show()这张图的价值在于帮助筛选规则。看右上角的点支持度高、置信度也高说明这些规则既常见又可靠优先考虑角落里支持度很低但置信度很高的点可能只是小样本上的巧合需要谨慎。我自己的经验是实际业务里通常牺牲一点置信度也要守住支持度否则规则应用场景太小没有商业意义。3.2 网络图谁和谁总是一起出现第二张图我习惯画规则网络图把商品之间的关联关系用图的方式呈现出来。节点是商品连线是规则线越粗表示提升度越高。import networkx as nx # 取前10条强规则避免网络太密看不清 top_rules rules_ap.head(10).copy() top_rules[antecedents] top_rules[antecedents].apply(lambda x: list(x)[0]) top_rules[consequents] top_rules[consequents].apply(lambda x: list(x)[0]) G nx.DiGraph() for _, row in top_rules.iterrows(): G.add_edge(row[antecedents], row[consequents], weightrow[lift]) plt.figure(figsize(10, 6)) pos nx.spring_layout(G, k1.2, seed42) weights [G[u][v][weight] for u, v in G.edges()] nx.draw_networkx_nodes(G, pos, node_color#5B9BD5, node_size1800) nx.draw_networkx_labels(G, pos, font_size12, font_colorwhite, font_weightbold) nx.draw_networkx_edges( G, pos, width[w * 4 for w in weights], edge_color#FF7F50, alpha0.7, arrowstyle-, arrowsize20 ) plt.title(频繁模式关联规则网络图Top 10) plt.axis(off) plt.tight_layout() plt.savefig(关联规则网络图.png, dpi150) plt.show()运行之后生成的图里你能清晰地看到“牛奶”这个节点周围连了“面包”“黄油”“鸡蛋”等多条边说明它是数据中的核心商品。做捆绑推荐时这类中心节点就是最佳切入点——把它放在货架中间或者推荐位首位带动效果最明显。3.3 图片保存与中文乱码问题上面代码里我都加了plt.savefig把图片保存成 PNG 文件方便直接贴到报告或论文里。有两个容易踩的坑第一中文乱码。matplotlib默认字体不支持中文如果注释或标题里有中文画出来就是一堆方块。解决办法是设plt.rcParams[font.sans-serif] [SimHei]Windows 一般没问题如果是 Mac把SimHei换成Arial Unicode MSLinux 系统需要先安装中文字体比如fonts-wqy-zenhei。第二图片清晰度。保存时把dpi调到至少 150期刊论文建议 300。屏幕上看着还行贴到 Word 里放大就模糊多半是dpi没设置。4. 参数解读与调优support、confidence、lift 怎么配合4.1 三个指标各自管什么频繁模式挖掘的结果里最常看的三个指标是支持度、置信度和提升度很多人一开始分不清我在这里用一个例子说透。以规则牛奶 - 面包为例。支持度是“同时买了牛奶和面包”的事务占总事务的比例它衡量规则的普遍性置信度是“买了牛奶的人里面又买了面包”的比例它衡量规则的可靠性提升度是“买牛奶时买面包的概率”除以“没买牛奶时买面包的概率”它衡量规则是否有实际价值。三个指标的取舍逻辑是这样的提升度等于 1 说明牛奶和面包相互独立这条规则没有意义大于 1 才说明有正相关。实际项目里支持度设太低了会挖出一堆冷门组合设太高了会漏掉有价值的细节规则。我一般会把支持度从 0.5 开始往下试每降 0.05 看一眼结果数量找到一个结果条数在几十条左右的阈值这样既不会爆炸也不会有太多遗漏。4.2 实际调参经验针对我这份模拟数据min_support0.3、min_threshold0.5是比较合适的组合。如果你换成自己的数据可以参考下面几条经验数据量小几千条事务以内支持度从 0.2 到 0.5 之间试探数据量大百万级支持度往往要降到 0.01 以下不然什么都挖不出来。关联规则的metric参数可以根据业务选。做推荐系统我更看重lift太低提升度的规则宁可不要做风控或异常检测反而关注置信度确保规则触发时足够可靠。max_len参数可以控制项集大小。如果只想看两两组合直接设max_len2如果关心组合购买比如“牛奶面包黄油”是不是经常一起买就保持默认。5. 常见问题与排查技巧实录写这一节是因为我亲手踩过不少坑。初学者最容易在半路卡住我把典型的几个问题和解决方案整理成了一张速查表。5.1 报错合集速查表报错信息原因解决方案ModuleNotFoundError: No module named mlxtend没有安装 mlxtend执行pip install mlxtendExpecting pandas DataFrame with 0/1 values直接传了列表或没有 0/1 编码用TransactionEncoder转换数据ValueError: The support column is missing频繁项集结果没有 support 列检查apriori或fpgrowth是否成功运行中文标题乱码matplotlib 默认字体不支持中文设置plt.rcParams[font.sans-serif]图片横坐标标签太密集看不清商品种类太多导致刻度重叠旋转标签plt.xticks(rotation45, haright)或者只显示部分标签5.2 画图横坐标太密集怎么办这个问题在热搜词里也出现了说明很多人卡在可视化上。当你用df.columns作为 x 轴标签时如果商品种类超过 20 个标签就会挤成一团。最简单的处理办法是加一行代码plt.xticks(rotation45, haright)把标签旋转 45 度基本能缓解。如果还是太挤则用plt.xticks(ticksrange(0, len(columns), 5))每隔 5 个显示一个标签。这两招对任何“横坐标太密集”的场景都适用。5.3 结果图片里的核心信息怎么解读很多人跑完代码图也出来了但不知道从图里读什么。基于我这份数据生成的两张图你至少应该关注三点图右上角是否有成片的点有说明规则整体质量不错网络图里度最高的节点是哪个它就是核心商品有没有某条规则的提升度特别高但支持度特别低这种规则需要人工判断是小概率事件还是真正的隐蔽关联。我在实际项目里遇到过一种情况某条规则提升度高达 8所有人都激动得不行结果把原始数据翻出来一看只是某两个月导入了两批关联订单数据属于系统性偏差并不是真实的购买习惯。所以挖出规则之后一定要回顾原始数据验证不要被统计数字带走。最后再分享一个小技巧mlxtend的规则结果里antecedents和consequents列是frozenset类型打印出来像frozenset({牛奶})不太好看。导出 CSV 之前可以做一个转换rules[antecedents] rules[antecedents].apply(lambda x: list(x)[0])把集合转成普通字符串后续处理数据、做 Excel 透视都会方便很多。这套代码跑出来的数据和图片足够支撑一篇完整的频繁模式挖掘实验报告想继续深入的朋友还可以把算法换成 ECLAT或者直接上pyspark的 FPGrowth 处理海量数据。本文还有配套的精品资源点击获取