资讯动态

MATLAB实战FP-Growth关联规则挖掘:从建树到规则生成

发布时间:2026/10/15 19:09:42 来源:尧图企业网站定制
简介这份资源是面向数据挖掘初学者与MATLAB使用者的FP-Growth关联规则挖掘实现包用于在交易数据中高效发现频繁项集并提取关联规则适合市场篮子分析、网络行为分析等场景的入门实践。压缩包共8个文件以7个.m脚本和1个.mat数据集为主整体约5KB其中脚本承担主流程调度、FP树构建、幂集与非平凡子集生成、规则展示及树结构可视化等职责mydata数据集则用于直接运行演示。已有191人学习下载。通过阅读与调试这些代码读者可以完整走通从数据预处理、设定最小支持度、构造FP树、生成条件模式基到递归挖掘与规则提取的全过程理解FP-Growth相较Apriori减少数据扫描次数的效率优势并可将mydata替换为自己的事务数据调整支持度阈值后快速迁移到实际挖掘任务中。1. 从一份 FP-Growth 压缩包说起matlab 关联规则挖掘到底能跑多快如果你手头有一份名为FP-Growth Assiciation Rule Mining.rar的资源包里面大概率是一套用 MATLAB 实现的频繁模式增长算法用来做关联规则挖掘。它解决的核心问题很具体给定一批事务数据比如购物篮、日志事件、故障码组合找出频繁共现的项集再从中导出「A 出现时 B 也容易出现」这类规则。适合谁做数据挖掘课程设计的学生、需要快速验证关联规则效果的分析人员以及不想从零手写 FP-Tree 的 MATLAB 用户。很多人第一次接触关联规则是从 Apriori 开始的但 Apriori 要反复扫描数据库事务一多就慢得让人怀疑人生。FP-Growth 的思路是把数据库压进一棵 FP-Tree只扫两遍后续挖掘全在树上递归进行速度提升非常明显。这份资源包的价值就在于它把建树、条件模式基、递归挖掘这条链路用 MATLAB 串了起来你拿到手就能替换自己的数据跑通而不是对着伪代码发呆。2. FP-Tree 构建与条件模式基MATLAB 里怎么把事务压成一棵树2.1 为什么选 FP-Growth 而不是 AprioriApriori 的逻辑是「逐层候选生成 全库验证」每增加一个项集长度就要重新扫一遍事务表。假设你有 10 万条事务、平均每条 20 个项Apriori 在候选集膨胀阶段会产生大量无效组合I/O 和内存双重压力。FP-Growth 的做法完全不同第一遍扫描统计每个项的支持度过滤掉低于最小支持度的项第二遍扫描把每条事务里的项按支持度降序排列依次插入一棵前缀树。树的每条路径代表一个项集节点上记录计数。这样数据库的共现信息被完整保留在树结构里后续挖掘不需要再碰原始数据。在 MATLAB 里实现时常见做法是用嵌套结构体或 containers.Map 来表示节点。结构体字段包括项名、计数、父节点索引、子节点映射。用 Map 存子节点比数组查找更快因为项名到子节点索引的映射是 O(1)。我一般会先把事务转成元胞数组每个元胞是一个字符串数组然后跑两遍循环完成建树。2.2 建树的核心代码与参数说明下面这段代码演示了 FP-Tree 节点的定义和插入逻辑是这类资源包里最关键的骨架% 定义 FP-Tree 节点结构 % name: 项名 count: 计数 parent: 父节点索引 children: Map项名, 子节点索引 function node createNode(name, count, parent) node struct(name, name, count, count, ... parent, parent, children, containers.Map()); end % 将一条事务插入 FP-Tree % transactions: 元胞数组每个元素是字符串数组 % minSupportCount: 最小支持度计数阈值 function [tree, root] buildFPTree(transactions, minSupportCount) % 第一遍统计支持度 itemCount containers.Map(KeyType,char,ValueType,double); for i 1:length(transactions) items unique(transactions{i}); % 同一事务内重复项只计一次 for j 1:length(items) if isKey(itemCount, items{j}) itemCount(items{j}) itemCount(items{j}) 1; else itemCount(items{j}) 1; end end end % 过滤低频项并按支持度降序排列 freqItems keys(itemCount); freqCounts cell2mat(values(itemCount)); validIdx freqCounts minSupportCount; freqItems freqItems(validIdx); freqCounts freqCounts(validIdx); [~, sortIdx] sort(freqCounts, descend); freqItems freqItems(sortIdx); rankMap containers.Map(freqItems, num2cell(1:length(freqItems))); % 第二遍建树 tree createNode(root, 0, 0); root 1; nodeList {tree}; for i 1:length(transactions) items transactions{i}; % 只保留频繁项并按支持度降序排列 validItems items(cellfun((x) isKey(rankMap, x), items)); [~, order] sort(cellfun((x) rankMap(x), validItems)); validItems validItems(order); currentNode root; for j 1:length(validItems) item validItems{j}; childMap nodeList{currentNode}.children; if isKey(childMap, item) childIdx childMap(item); nodeList{childIdx}.count nodeList{childIdx}.count 1; else newNode createNode(item, 1, currentNode); nodeList{end1} newNode; childIdx length(nodeList); childMap(item) childIdx; nodeList{currentNode}.children childMap; end currentNode childIdx; end end tree nodeList; end逻辑说明第一遍循环统计每个项的出现次数unique保证同一事务内重复项不重复计数。第二遍循环里rankMap把项名映射到支持度排名排序后依次插入。插入时如果当前节点的子节点 Map 里已有该项就增加计数否则新建节点并挂到父节点下。参数minSupportCount是绝对计数阈值通常由最小支持度乘以事务总数得到。比如 1000 条事务、最小支持度 0.05阈值就是 50。这个值设得太高会漏掉长尾规则设得太低会导致树爆炸、递归深度过大。2.3 条件模式基的提取方式建完树之后挖掘频繁项集需要从每个频繁项出发沿着节点头表找到所有包含该项的路径截取从根到该节点的前缀路径形成条件模式基。在 MATLAB 里如果没建头表可以遍历所有节点对每个频繁项收集其祖先路径。常见做法是维护一个headerTable用 Map 把项名映射到节点索引列表。每次插入新节点时把节点索引追加到对应项的列表里。提取条件模式基时对每个节点沿parent指针向上走直到根节点把路径上的项和该节点的计数组成一条条件事务。这一步的坑在于路径上的计数应该取该节点的计数而不是路径上各节点的计数。因为条件模式基代表的是「以该项为后缀」的事务子集计数由后缀节点决定。很多手写实现在这里翻车导致频繁项集计数偏大。3. 从频繁项集到关联规则支持度、置信度与提升度的 MATLAB 落地3.1 递归挖掘频繁项集的实现FP-Growth 的递归挖掘函数接收一棵 FP-Tree 和当前后缀项集输出所有频繁项集。核心步骤是对每个频繁项提取条件模式基用条件模式基建一棵条件 FP-Tree如果条件 FP-Tree 不是单路径就继续递归如果是单路径直接枚举所有组合。% 递归挖掘频繁项集 % nodeList: 节点列表 headerTable: 项名到节点索引列表的映射 % minSupportCount: 最小支持度计数 suffix: 当前后缀项集 % freqItemsets: 输出频繁项集每个元素是 struct(items, {}, support, {}) function freqItemsets mineFPTree(nodeList, headerTable, minSupportCount, suffix, freqItemsets) items keys(headerTable); for i 1:length(items) item items{i}; nodeIdxs headerTable(item); % 收集条件模式基 condTransactions {}; for k 1:length(nodeIdxs) nodeIdx nodeIdxs(k); count nodeList{nodeIdx}.count; path {}; p nodeList{nodeIdx}.parent; while p ~ 0 ~strcmp(nodeList{p}.name, root) path{end1} nodeList{p}.name; p nodeList{p}.parent; end if ~isempty(path) condTransactions{end1} path; condTransactions{end1} count; % 用元胞存计数 end end % 构建条件 FP-Tree 并递归 newSuffix [suffix, {item}]; support sum(cell2mat(condTransactions(2:2:end))); freqItemsets{end1} struct(items, {newSuffix}, support, support); % 如果条件模式基非空继续递归 if length(condTransactions) 2 % 这里需要把 condTransactions 转成事务列表重新建树 % 实际代码中会调用 buildFPTree 的变体 end end end逻辑说明headerTable的每个键对应一个频繁项值是该项在树中所有节点的索引列表。对每个节点沿父指针向上收集路径路径上的项就是条件模式基。support是该后缀项集的总支持度计数。递归终止条件是条件模式基为空或只包含单条路径。参数minSupportCount在递归过程中保持不变但条件 FP-Tree 的建树阈值仍然是它因为条件模式基里的计数已经反映了原始事务的频次。3.2 关联规则的生成与三个度量指标频繁项集挖出来之后生成关联规则就是枚举每个频繁项集的所有非空真子集计算置信度和提升度。假设项集{A, B, C}的支持度是s子集{A, B}的支持度是s1那么规则{A, B} - {C}的置信度是s / s1提升度是s / (s1 * s_C / N)其中s_C是{C}的支持度N是事务总数。指标公式含义调参建议支持度count / N项集出现的频率从 0.01 起步数据稀疏时降到 0.005置信度support(X∪Y) / support(X)X 出现时 Y 也出现的概率常用 0.50.8太低规则不可信提升度confidence / support(Y)规则是否比随机猜测好大于 1 才有正相关小于 1 说明负相关在 MATLAB 里可以用nchoosek枚举子集但要注意项集长度超过 10 时组合数会爆炸。常见做法是只对长度不超过 4 的频繁项集生成规则或者用剪枝策略如果某个子集的置信度已经低于阈值它的超集规则也不用算了。3.3 规则筛选与排序的实操建议跑完挖掘后你可能会得到几千条规则。直接看根本看不过来。我一般会按提升度降序排然后过滤掉提升度小于 1.2 的规则再按置信度做二次排序。如果规则里出现「全集项」——也就是支持度等于事务总数的项比如「购物袋」这种每条事务都有的项——要手动剔除否则它会出现在大量规则的右边毫无信息量。另一个实操点是对规则做分组。比如按右侧项分组看每个目标项被哪些前置项触发。这在故障诊断场景里特别有用你想知道「哪些故障码组合会导致某个严重故障」按右侧项分组后一目了然。4. 避坑与排查MATLAB 跑 FP-Growth 最常见的五类翻车4.1 支持度阈值设太低导致内存溢出现象程序跑到一半 MATLAB 报「Out of memory」或者递归深度过大触发「Maximum recursion limit reached」。 原因最小支持度设得太低频繁项数量激增FP-Tree 节点数膨胀条件模式基的递归层数也跟着涨。 解决先用支持度 0.05 跑一遍看频繁项数量如果超过 5000 个说明阈值太低。逐步提高到 0.1 或 0.2观察规则数量变化。另一个办法是限制项集最大长度在递归函数里加一个maxLen参数超过就返回。4.2 事务内重复项导致计数偏大现象某个项的支持度计数比实际事务数还大。 原因建树时没有对同一事务内的项去重同一个项在一条事务里出现两次就被计了两次。 解决在统计支持度和插入树之前对每条事务调用unique。注意unique会改变顺序所以要在排序之前做。如果业务上重复项有意义比如数量那应该把项名和数量拼成一个新项而不是让同一个项名出现多次。4.3 条件模式基的计数取错节点现象频繁项集的支持度比预期大很多规则置信度超过 1。 原因提取条件模式基时路径上每个节点的计数被累加了而不是取后缀节点的计数。 解决条件模式基里每条路径的计数应该等于该路径末端节点的计数。路径中间的节点计数代表的是包含更长后缀的事务数不能直接用。检查代码里count变量是不是从nodeList{nodeIdx}.count取的。4.4 项名排序不稳定导致树结构不一致现象同样的数据跑两次得到的频繁项集数量不一样。 原因支持度相同的项在排序时顺序不稳定MATLAB 的sort对相同值的元素不保证原始顺序。 解决在按支持度降序排列后对支持度相同的项再按项名字典序排一次。这样每次建树的顺序完全一致结果可复现。代码里加一行[~, idx] sortrows([-freqCounts, freqItems], [1, 2])之类的二次排序。4.5 规则生成阶段组合爆炸现象频繁项集挖完了但生成规则时卡死。 原因一个长度为 15 的频繁项集有 2^15 - 2 32766 个非空真子集逐个计算置信度非常慢。 解决限制频繁项集的最大长度或者在生成规则前先按支持度过滤掉长项集。另一个策略是只生成右侧为单项的规则这样组合数从 2^n 降到 n速度快很多而且大多数场景下单项规则更容易解释。5. 进阶技巧用 MATLAB 把 FP-Growth 封装成可复用函数5.1 输入输出接口设计把整个流程封装成一个函数输入是事务元胞数组和参数结构体输出是频繁项集表和规则表。参数结构体里放minSupport、minConfidence、maxItemsetLen、maxRuleLen。输出用 MATLAB 的table类型方便后续筛选和导出。function [freqTable, ruleTable] fpGrowthMining(transactions, params) % 参数默认值 if ~isfield(params, minSupport), params.minSupport 0.05; end if ~isfield(params, minConfidence), params.minConfidence 0.6; end if ~isfield(params, maxItemsetLen), params.maxItemsetLen 4; end N length(transactions); minCount ceil(params.minSupport * N); % 建树与挖掘 [nodeList, headerTable] buildFPTree(transactions, minCount); freqItemsets mineFPTree(nodeList, headerTable, minCount, {}, {}); % 转成 table itemsStr cellfun((x) strjoin(x, ,), ... cellfun((x) x.items, freqItemsets, UniformOutput, false), ... UniformOutput, false); supports cellfun((x) x.support, freqItemsets); freqTable table(itemsStr, supports, VariableNames, {Itemset, Support}); % 生成规则 ruleTable generateRules(freqItemsets, params.minConfidence, N); end逻辑说明minCount用ceil向上取整避免支持度刚好等于阈值时被过滤掉。freqItemsets是元胞数组每个元素是结构体包含项集和支持度。转table时把项集用逗号拼成字符串方便查看。generateRules是单独的函数负责枚举子集、计算置信度和提升度、按阈值过滤。5.2 用真实场景数据验证拿一份超市购物篮数据测试1000 条事务平均每条 8 个商品最小支持度 0.03最小置信度 0.5。跑完之后看规则表按提升度排序。如果发现「牛奶 - 面包」这种规则提升度只有 1.05说明两者几乎独立不用关注。如果「啤酒 - 尿布」提升度到 2.3那就是强关联值得深挖。验证方法手动抽几条规则回到原始事务里数一下共现次数和程序输出的支持度对一下。如果对不上大概率是条件模式基的计数取错了回到 4.3 排查。5.3 性能调优的几个习惯第一把事务数据转成数值索引再建树比用字符串快很多。做法是维护一个项名到整数的 Map建树时只存整数输出结果时再映射回字符串。第二递归函数里尽量少用containers.Map因为 MATLAB 的 Map 在深层递归里开销不小。可以用数组加二分查找替代。第三如果数据量特别大考虑把 FP-Tree 的节点存成并行数组names、counts、parents、children分开存减少结构体嵌套。从那以后我每次跑关联规则之前都会先用小样本比如 100 条事务跑一遍全流程确认支持度、置信度、提升度的计算逻辑没问题再上全量数据。这个习惯帮我省了很多次「跑了一小时发现结果全错」的后悔药。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑