FP-Growth算法通过构建FP-Tree实现高效频繁项集挖掘:仅需两次数据库扫描,不生成候选集,利用压缩树结构与条件模式基递归挖掘,显著优于Apriori。

直接用 FP-Growth,别碰 Apriori —— 对百万级事务、上千维项集,Apriori 的候选集爆炸和多次全量扫描会卡死进程,而 FP-Growth 仅需两次扫描、内存中建树递归挖掘,实测快一个数量级。
为什么 FP-Growth 在大规模离散序列上更稳?
核心在于它不生成候选集,而是把事务压缩进一棵 FP-tree:每个节点存项名 + 计数 + 父子指针 + 同项链表头(node_link)。这使得高频项天然聚拢,路径回溯即得条件模式基,避免了 Apriori 中 O(2^k) 候选集生成和反复扫描的开销。
但注意:原始 FP-Growth 默认处理「集合型事务」(如 ['milk', 'bread']),若你的数据是「序列型」(如用户点击流 ['home', 'search', 'product', 'cart']),必须先做预处理:
- 按业务含义切分「事务单位」:是每个用户单日行为算一条事务?还是每次会话(session)?不能直接把整条长序列当一个事务喂进去
- 对每条事务去重:序列中重复项(如连续点击同一按钮)要合并为单次出现,否则
FP-tree会误判支持度 - 过滤低频项:先全局统计项频次,剔除低于
min_support的项,再重建事务——这步能显著缩小树规模
mlxtend.frequent_patterns.fpgrowth 的坑与绕法
很多人直接用 mlxtend 库的 fpgrowth 函数,结果报 MemoryError 或跑出空结果。常见原因:
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
立即学习“Python免费学习笔记(深入)”;
-
use_colnames=True时传入的是布尔型 DataFrame,但列名含特殊字符(如空格、斜杠)会导致内部pd.get_dummies失败 → 改用纯英文下划线命名列,或提前df.columns = df.columns.str.replace(r'[^a-zA-Z0-9_]', '_') -
min_support设太小(如0.001)导致频繁项过多,树节点超亿级 → 先用value_counts(normalize=True)看项分布,把阈值设在前 5% 项的最小频次之上 - 输入 DataFrame 行数极大但稀疏度高(比如 100 万行 × 5000 列,但每行平均仅 3 个
True)→ 改用scipy.sparse.csr_matrix构造输入,mlxtend支持该格式且省内存
自己实现轻量 FP-tree 时的关键取舍
当 mlxtend 仍扛不住(比如 5000 万事务),就得手写精简版。重点控制三处内存和时间:
- 节点不存完整路径,只存
value、count、parent、children: dict;node_link用全局字典{item: head_node}管理,避免每个节点冗余字段 - 构建条件 FP-tree 时,不复制节点,而是复用原树节点指针 + 新计数;递归时用栈模拟(防深递归爆栈)
- 输出只保留长度 ≥2 且支持度 ≥
min_support的项集,跳过所有单一项——它们对关联规则无意义,还占大量输出带宽
真正难的不是建树,是定义“事务”边界和清洗项粒度。比如电商日志里 'add_to_cart' 和 'add_to_cart_v2' 算同一项吗?用户 ID 是否该哈希后截断?这些业务逻辑决定结果是否可用,算法本身只是执行器。

















