ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

FP-growth算法实战:Python购物篮分析、FP树可视化与避坑指南

FP-growth算法实战:Python购物篮分析、FP树可视化与避坑指南 简介这份资源面向数据挖掘与机器学习初学者及需要落地关联规则分析的开发者围绕FP-growth频繁模式增长算法提供Python实现与FP树可视化工具可用于购物篮分析、频繁项集挖掘与大型数据库中的频繁模式发现。压缩包共11个文件、约480KB包含py主程序与whl依赖包用于算法运行csv交易数据用于购物篮分析实验png可视化结果展示FP树结构md与docx文档补充说明与扩展资料txt记录环境与使用要点。已有76人学习下载。读者可据此理解FP树构建与递归挖掘频繁项集的完整流程对比Apriori算法两次扫描数据库的效率优势并借助可视化直观观察频繁项集的组织方式进而将关联规则应用于商品布局优化、交叉销售与个性化推荐等场景形成从算法原理到代码实践再到结果解读的闭环。1. 从一份购物篮数据说起FP-growth 到底比 Apriori 快在哪如果你手头有一份几十万行的超市交易流水想找出「买了尿布的顾客还会买什么」用 Apriori 跑一遍大概率会让你等到怀疑人生。原因不复杂Apriori 每一轮候选集生成都要重新扫全表k 大一点扫描次数就跟着涨I/O 直接成为瓶颈。FP-growth 换了个思路——它把整个事务库压缩进一棵 FP 树Frequent Pattern Tree全库只扫两遍之后所有挖掘都在内存里的树上递归完成不再反复读盘。这份资源就是一套基于 Python 的 FP-growth 实现加可视化工具核心文件是FPTree.py配套GoodsOrder.csv、GoodsTypes.csv两份购物篮样例数据还带了一个pygraphviz的 Windows 轮子能把建好的 FP 树直接画成图。它适合两类人一类是正在学数据挖掘、想亲手把 FP 树建出来看看到底长什么样的学生和转行者另一类是手上真有交易数据、想快速验证关联规则能不能挖出东西的从业者。下面我按「先跑通、再拆原理、最后避坑」的顺序把这份包从头到尾过一遍。2. 环境搭起来从 requirements 到 pygraphviz 轮子的安装顺序2.1 先看清楚包里有什么别急着 pip install拿到压缩包解压后目录结构大致是这样FPTree.py是算法主文件FPTree-main是工程目录GoodsOrder.csv存的是订单号到商品名的映射GoodsTypes.csv存的是商品类别requirements.txt列了依赖pygraphviz-1.5-cp37-cp37m-win_amd64.whl是专门给 Windows Python 3.7 准备的轮子demo目录下有两张输出图output_6_0.png、output_13_0.png还有一份基于fp-tree实现购物篮分析【可视化】.md的说明文档。这里第一个要提醒的点pygraphviz是这份包里最容易翻车的一环。它底层依赖 Graphviz 的 C 库直接pip install pygraphviz在 Windows 上十有八九会报编译错误。包作者很贴心地塞了一个cp37-cp37m-win_amd64的 whl意思是这个轮子只对 Python 3.7、64 位 Windows 有效。如果你用的是 Python 3.8 以上这个 whl 装不上得自己去找对应版本的轮子或者改用graphvizpydot的方案。先看依赖清单# 查看依赖确认版本约束 cat requirements.txt常见的输出会包含numpy、pandas、graphviz、pygraphviz这几项。pandas用来读 CSVnumpy做数组运算graphviz和pygraphviz负责画树。逻辑上算法本身只依赖标准库就能跑可视化才是额外依赖所以如果你只想验证频繁项集可以先跳过 pygraphviz。2.2 分步安装把可视化依赖单独处理我一般会分两步走先保证算法能跑再补可视化。这样即使画图环境没配好也不影响你验证结果。# 第一步建虚拟环境避免污染全局 python -m venv fp_env # Windows 激活 fp_env\Scripts\activate # Linux / macOS 激活 source fp_env/bin/activate # 第二步装基础依赖 pip install pandas numpy graphviz # 第三步Windows Python 3.7 直接装包里的轮子 pip install pygraphviz-1.5-cp37-cp37m-win_amd64.whl # 非 3.7 环境尝试源码安装需先装 Graphviz 本体并配好 PATH pip install pygraphviz参数说明python -m venv创建隔离环境避免和你系统里已有的包版本打架pip install pygraphviz-1.5-...whl是本地轮子安装不走网络编译成功率高源码安装那条要求你先去 Graphviz 官网装好本体并把bin目录加进系统 PATH否则会报graphviz/cgraph.h: No such file or directory。装完之后验证一下# verify_env.py import pandas as pd import numpy as np try: import pygraphviz print(pygraphviz OK, version:, pygraphviz.__version__) except ImportError: print(pygraphviz 未安装可视化功能不可用算法仍可运行)这段代码的作用是快速判断可视化依赖是否就位。如果打印出未安装不用慌FPTree.py里的挖掘逻辑照样能跑只是画不出树。2.3 用样例数据跑通第一次挖掘环境好了直接拿包里的GoodsOrder.csv跑一遍。先看一眼数据长什么样# peek_data.py import pandas as pd order pd.read_csv(GoodsOrder.csv, encodinggbk) print(order.head()) print(总行数:, len(order)) print(列名:, order.columns.tolist())逻辑说明encodinggbk是因为这类中文商品数据在 Windows 上导出时常见 GBK 编码直接utf-8读会报UnicodeDecodeError。head()看前五行确认字段len()确认数据规模。参数上如果你的 CSV 是 UTF-8把 encoding 换成utf-8即可。确认数据没问题后调用主算法# run_fpgrowth.py from FPTree import FPTree # 读取交易数据按订单号聚合成事务列表 df pd.read_csv(GoodsOrder.csv, encodinggbk) transactions df.groupby(订单号)[商品].apply(list).tolist() # 最小支持度计数注意这里是计数不是比例 min_support 100 tree FPTree(transactions, min_support) freq_items tree.mine_frequent_itemsets() for itemset, count in freq_items.items(): print(itemset, count)逻辑说明groupby(订单号)[商品].apply(list)把扁平的「订单-商品」两列数据聚成「一个订单一个商品列表」的事务格式这是 FP-growth 的标准输入。min_support传的是绝对计数不是 0.01 这种比例这是很多人第一次用会搞混的地方——传比例进去会导致频繁项集为空或者结果完全不对。mine_frequent_itemsets()返回的是字典键是项集元组值是支持度计数。跑通这一步你已经完成了从数据到频繁项集的完整链路。接下来才是理解它内部到底干了什么。3. 拆开 FPTree.py两次扫描、树构建与递归挖掘的实现细节3.1 第一遍扫描定频率第二遍扫描建树FP-growth 的精髓在于「只扫两遍库」。第一遍扫全表统计每个单品出现的次数砍掉低于 min_support 的项剩下的按频率降序排成一张头表header table。第二遍扫全表对每条事务里的商品按头表顺序重排然后逐条插入 FP 树公共前缀共享节点计数累加。为什么频率降序这么关键因为降序能让高频项尽量靠近树根公共前缀最大化树就被压得越扁后续递归挖掘时条件模式基越短效率越高。如果顺序乱了树会退化成接近链表的结构压缩效果荡然无存。# 头表构建的核心逻辑简化示意 def build_header_table(transactions, min_support): counts {} for trans in transactions: for item in trans: counts[item] counts.get(item, 0) 1 # 过滤低频项并按计数降序 header {k: v for k, v in counts.items() if v min_support} return dict(sorted(header.items(), keylambda x: x[1], reverseTrue))逻辑说明counts.get(item, 0) 1做累加统计字典推导式过滤掉不满足最小支持度的项sorted(..., reverseTrue)保证降序。参数min_support直接决定头表大小——调高头表变短、树变小、挖掘快但可能漏掉长尾规则调低头表变长、树变大、能挖出更多规则但内存和耗时上升。3.2 节点结构与条件模式基的递归FP 树的每个节点存三样东西项名、计数、指向父节点和同名节点的指针。同名节点指针node link把所有相同的项串成一条链方便从底向上找条件模式基。挖掘时从频率最低的项开始沿着 node link 往上爬到根收集所有前缀路径每条路径的计数取该节点自身的计数这就构成了条件模式基。# 条件模式基收集的简化逻辑 def get_conditional_pattern_base(node): patterns [] while node is not None: path [] parent node.parent while parent is not None and parent.item is not None: path.append(parent.item) parent parent.parent if path: patterns.append((path, node.count)) node node.node_link return patterns逻辑说明内层while从当前节点往上走到根收集前缀路径node.count是该路径在条件模式基里的权重外层while沿 node link 处理所有同名节点。注意根节点通常用None或特殊标记表示循环里要排除掉否则会把空根算进路径。拿到条件模式基后把它当成一个新的「小事务库」递归建子树、再挖掘直到没有频繁项为止。这就是 FP-growth 不需要生成候选集的原因——它直接在压缩结构上分治。3.3 从频繁项集到关联规则置信度和提升度怎么算频繁项集只是半成品真正能指导业务的是关联规则。规则A - B的置信度是support(A∪B) / support(A)意思是买了 A 的人里有多大比例也买了 B。但置信度高不代表有价值还得看提升度lift confidence / support(B)lift 大于 1 才说明 A 和 B 正相关等于 1 说明独立小于 1 说明负相关。# 生成关联规则并计算置信度、提升度 def generate_rules(freq_items, min_conf0.5): rules [] for itemset, sup in freq_items.items(): if len(itemset) 2: continue for i in range(1, len(itemset)): for antecedent in combinations(itemset, i): consequent tuple(set(itemset) - set(antecedent)) conf sup / freq_items[antecedent] lift conf / (freq_items[consequent] / total_transactions) if conf min_conf: rules.append((antecedent, consequent, conf, lift)) return rules逻辑说明combinations(itemset, i)枚举所有非空真子集作为前件conf用项集支持度除以前件支持度lift再除以后件的全局支持度。参数min_conf是置信度门槛一般从 0.5 起步业务上要求高可信就调到 0.7 以上。total_transactions是事务总数算后件支持度时要用到。这里有个容易忽略的点freq_items[antecedent]要求前件本身也在频繁项集字典里。因为前件是项集的子集而频繁项集的向下封闭性保证了子集也频繁所以正常情况下不会 KeyError。但如果你手动构造了不完整的 freq_items就会翻车。4. 可视化与购物篮分析把 FP 树画出来把规则讲清楚4.1 用 pygraphviz 渲染 FP 树可视化是这份包区别于纯算法代码的亮点。FPTree.py里通常有一个render_tree或类似方法把树节点和边导出成 DOT 格式再交给 pygraphviz 渲染成 PNG。包里的output_6_0.png和output_13_0.png就是不同支持度下的输出示例文件名里的数字一般对应 min_support 或迭代轮次。# 渲染 FP 树为 PNG import pygraphviz as pgv def render_tree(tree, filenamefp_tree.png): G pgv.AGraph(directedTrue, strictFalse) def add_node(node, parent_idNone): if node.item is None: return node_id f{node.item}_{id(node)} G.add_node(node_id, labelf{node.item}:{node.count}) if parent_id: G.add_edge(parent_id, node_id) for child in node.children: add_node(child, node_id) for child in tree.root.children: add_node(child) G.draw(filename, progdot, formatpng)逻辑说明AGraph(directedTrue)建有向图节点标签用项名:计数的格式一眼能看出每个节点被经过多少次progdot指定 Graphviz 的层次布局引擎画出来的树是自上而下的层级结构比默认布局清晰得多。参数formatpng可以换成svg或pdf看你要嵌到哪。如果节点太多导致图糊成一团常见做法是提高 min_support 让树变小或者只渲染前 N 层。我一般会先用高支持度画一张全局图看结构再降支持度看细节。4.2 购物篮分析的完整链路与结果解读把前面几步串起来一份购物篮分析的完整流程是读数据 → 聚合事务 → 定支持度 → 建树 → 挖频繁项集 → 生成规则 → 按提升度排序 → 可视化。下面这张表是我常用的参数起点你可以照着调参数含义建议起点调整方向min_support最小支持度计数总事务数的 1%~5%数据稀疏调低规则太多调高min_conf最小置信度0.5要强规则调到 0.7min_lift最小提升度1.0过滤掉独立和负相关规则max_len规则最大长度3~4太长规则业务解释性差解读结果时别只看置信度。举个例子「买牙膏 - 买牙刷」置信度可能高达 0.9但牙刷本身买的人就多lift 可能只有 1.1这种规则业务价值有限。反过来某个小众商品组合 lift 到 3 以上哪怕支持度不高也可能是交叉销售的突破口。这就是为什么我坚持把 lift 一起算出来排序。4.3 换自己的数据要改哪几处包里的样例数据是「订单号 商品」两列格式。如果你手上是宽表一行一个订单多列商品得先 melt 成长表如果是「订单号 商品 数量」要决定数量是忽略还是作为权重。常见做法是忽略数量只关心买没买因为 FP-growth 的标准模型是布尔关联。# 宽表转长表 wide pd.read_csv(my_orders.csv) long_df wide.melt(id_vars[订单号], var_name列, value_name商品).dropna() transactions long_df.groupby(订单号)[商品].apply(list).tolist()逻辑说明melt把多列商品压成两列dropna()去掉空值因为宽表里没买的格子通常是 NaN再按订单号聚合。改完这一步后面的建树和挖掘代码一行都不用动。5. 避坑与排查这份包最容易翻车的五个地方5.1 现象pygraphviz 装不上报编译错误原因pygraphviz 依赖 Graphviz 的 C 头文件pip 源码安装时找不到graphviz/cgraph.h或者 Python 版本和包里的 whl 不匹配whl 是 cp37你用的是 3.9/3.10。解决优先用包里的 whl确认你的 Python 是 3.7 且 64 位。版本不符就去装 Graphviz 本体把安装目录\bin加进 PATH再pip install --global-optionbuild_ext --global-option-I安装目录\include pygraphviz。实在搞不定就放弃 pygraphviz改用graphviz库输出 DOT 文本用在线或本地 Graphviz 命令行渲染。5.2 现象频繁项集为空或者只有单个商品原因min_support 传成了比例比如 0.01但代码期望的是绝对计数。0.01 作为计数意味着要求某个商品出现至少 0.01 次逻辑上所有项都满足但后续比较时又可能因为类型问题全部被过滤。解决先算总事务数再乘比例得到计数。比如 10000 条事务想要 1% 的支持度就传 100。跑之前打印一下len(transactions)确认规模。5.3 现象读 CSV 报 UnicodeDecodeError原因中文数据在 Windows 上常见 GBK 或 GB2312 编码代码默认用 UTF-8 读。解决pd.read_csv(path, encodinggbk)如果还报错就试gb18030它兼容性更广。不确定编码可以用chardet检测或者用记事本另存为 UTF-8。5.4 现象树画出来节点重叠、看不清原因min_support 太低树节点成百上千Graphviz 布局挤在一起。解决提高 min_support 先看整体结构或者限制渲染深度只画前几层。也可以在G.draw里加args-Gnodesep0.5 -Granksep1.0调整节点间距和层间距。5.5 现象规则一大堆但业务上看不出价值原因只按置信度排序没算提升度导致大量「高频商品 - 高频商品」的无效规则排在前面。解决生成规则时同时算 lift过滤掉 lift 1 的再按 lift 降序排。业务上还可以加一层约束比如前件或后件必须包含某个重点品类缩小到可执行的规则集。6. 进阶技巧用支持度扫描找到那份数据的「甜点区」跑通之后最有价值的动作不是急着看规则而是做一次支持度扫描找到这份数据合适的 min_support。支持度定太高规则太少没洞察定太低规则爆炸还慢。我的习惯是从总事务数的 5% 开始每次减半往下试记录每个档位的频繁项集数量和耗时画一条曲线拐点附近就是甜点区。# 支持度扫描找合适阈值 import time total len(transactions) results [] for ratio in [0.05, 0.025, 0.01, 0.005, 0.002]: ms int(total * ratio) start time.time() tree FPTree(transactions, ms) freq tree.mine_frequent_itemsets() elapsed time.time() - start results.append((ratio, ms, len(freq), round(elapsed, 2))) print(f支持度比例 {ratio}, 计数 {ms}, 频繁项集 {len(freq)}, 耗时 {elapsed:.2f}s)逻辑说明ratio是支持度比例ms换算成绝对计数每个档位重新建树挖掘记录项集数量和耗时。参数上如果某个档位耗时突然从几秒跳到几十秒说明树已经大到内存吃紧该往回退了。这张扫描表比任何教程都更能告诉你这份数据的「密度」——稀疏数据可能 1% 就只剩几十个项集稠密数据 0.5% 还能挖出上万条。还有一个我踩过的坑不同支持度下挖出的规则不能直接横向比较数量因为项集空间本身在变。正确的做法是固定一个业务上可解释的支持度然后在这个基础上调置信度和提升度。从那以后我每次拿到新数据集都强制先跑一遍支持度扫描再决定后续参数不再拍脑袋定阈值。可视化那边也有个进阶玩法把 lift 最高的前若干条规则单独画成网络图节点是商品边是规则边宽表示 lift这样一眼能看出哪些商品是关联网络里的枢纽。包里的 pygraphviz 同样能画这种图把AGraph的节点换成商品、边换成规则即可比画 FP 树更贴近业务汇报的场景。希望帮到你。本文还有配套的精品资源点击获取
返回列表