别再死记硬背了!用Python手把手带你复现Apriori、FP-Growth算法(附完整代码与超市购物篮分析案例)
用Python实战Apriori与FP-Growth从超市购物篮到算法本质在超市收银台前我们常看到买了尿布的顾客也会购买啤酒这类看似奇怪的组合推荐。这背后正是关联规则挖掘的魔力——而Apriori和FP-Growth作为两大经典算法正是解开这种商业密码的钥匙。本文将以Python为工具带你从零实现这两个算法并用真实的超市购物篮数据验证其威力。1. 关联规则挖掘的核心概念关联规则挖掘的本质是发现事务数据中项与项之间的有趣关系。想象超市的每一笔交易都是一个购物篮我们需要找出哪些商品经常被同时购买。这需要理解三个关键指标支持度(Support): 项集出现的频率。比如100笔交易中有30笔同时包含牛奶和面包则支持度为30%置信度(Confidence): 规则的可信程度。如买牛奶→买面包的置信度 同时买两者的交易数 / 买牛奶的交易数提升度(Lift): 规则的有效性。计算为置信度 / 面包的独立购买概率大于1表示正相关在Python中我们可以用字典结构表示交易数据transactions [ {牛奶, 面包, 尿布}, {可乐, 面包, 啤酒}, {牛奶, 尿布, 啤酒}, {面包, 牛奶, 尿布, 啤酒}, {面包, 牛奶, 尿布} ]注意实际应用中数据通常存储在CSV或数据库表中需要先转换为这种集合形式2. Apriori算法实现与优化Apriori基于频繁项集的所有子集也必须是频繁的这一先验性质通过逐层搜索发现频繁项集。其Python实现可分为三个关键步骤2.1 生成候选项集def generate_candidates(itemsets, length): 生成指定长度的候选项集 candidates set() for i in itemsets: for j in itemsets: if len(i.union(j)) length: candidates.add(i.union(j)) return candidates2.2 计算支持度def calculate_support(itemset, transactions): 计算项集支持度 count sum(1 for t in transactions if itemset.issubset(t)) return count / len(transactions)2.3 剪枝策略def prune(itemsets, candidates, min_support, transactions): 剪枝不满足最小支持度的候选项集 frequent [] for candidate in candidates: support calculate_support(candidate, transactions) if support min_support: frequent.append((candidate, support)) return frequentApriori的主要性能瓶颈在于需要多次扫描数据库。我们可以通过以下优化策略提升效率优化策略实现方法效果提升事务压缩删除不包含任何候选项的事务减少扫描量分区技术将数据分为可装入内存的块减少I/O开销采样方法在数据子集上运行算法快速获取近似结果3. FP-Growth算法深度解析FP-Growth通过构建频繁模式树(FP-tree)避免生成候选项集其核心优势在于两次数据库扫描第一次统计项频次第二次构建FP-tree压缩存储共享前缀路径大幅减少存储需求分治策略通过条件模式基递归挖掘3.1 FP-tree构建class TreeNode: def __init__(self, name, count, parent): self.name name # 项名称 self.count count # 计数值 self.parent parent # 父节点 self.children {} # 子节点 self.link None # 横向链接 def build_fptree(transactions, min_support): # 第一次扫描统计项频次 item_counts defaultdict(int) for trans in transactions: for item in trans: item_counts[item] 1 # 过滤非频繁项并排序 freq_items {item for item, count in item_counts.items() if count min_support * len(transactions)} header_table {item: [count, None] for item, count in item_counts.items() if item in freq_items} # 第二次扫描构建FP-tree root TreeNode(null, 1, None) for trans in transactions: # 按频次排序并过滤 ordered_items [item for item in sorted(trans, keylambda x: (-item_counts[x], x)) if item in freq_items] if len(ordered_items) 0: update_tree(ordered_items, root, header_table) return root, header_table3.2 挖掘条件模式基def mine_fptree(header_table, min_support, prefix, frequent_itemsets): 递归挖掘频繁项集 items [item[0] for item in sorted(header_table.items(), keylambda x: (x[1][0], x[0]))] for item in items: new_prefix prefix.copy() new_prefix.add(item) frequent_itemsets.append((new_prefix, header_table[item][0])) # 构建条件模式基 cond_patt_base find_prefix_path(item, header_table) cond_tree, cond_header build_fptree(cond_patt_base, min_support) if cond_header is not None: mine_fptree(cond_header, min_support, new_prefix, frequent_itemsets)4. 实战超市购物篮分析让我们用真实的超市交易数据集包含7500条交易记录来验证算法效果。数据集格式如下交易ID商品列表1牛奶,面包,鸡蛋2面包,啤酒,尿布......4.1 数据预处理import pandas as pd from mlxtend.preprocessing import TransactionEncoder # 加载数据 df pd.read_csv(groceries.csv) transactions df[items].apply(lambda x: x.split(,)).tolist() # 转换为one-hot编码 te TransactionEncoder() te_ary te.fit(transactions).transform(transactions) df_encoded pd.DataFrame(te_ary, columnste.columns_)4.2 使用mlxtend库快速实现from mlxtend.frequent_patterns import apriori, fpgrowth # Apriori算法 freq_itemsets_ap apriori(df_encoded, min_support0.05, use_colnamesTrue) # FP-Growth算法 freq_itemsets_fp fpgrowth(df_encoded, min_support0.05, use_colnamesTrue) # 生成关联规则 from mlxtend.frequent_patterns import association_rules rules association_rules(freq_itemsets_fp, metriclift, min_threshold1.2)4.3 结果分析与可视化典型的高提升度规则示例前件后件支持度置信度提升度{酸奶}{水果}0.0560.4222.32{啤酒}{薯片}0.0720.3811.98{尿布}{婴儿食品}0.0630.5173.45import matplotlib.pyplot as plt plt.scatter(rules[support], rules[confidence], alpha0.5, crules[lift], cmapYlOrRd) plt.xlabel(Support) plt.ylabel(Confidence) plt.colorbar(labelLift) plt.title(关联规则三维关系图) plt.show()5. 算法对比与选型指南Apriori与FP-Growth在实际应用中各有优劣特性AprioriFP-Growth基本原理广度优先搜索频繁模式树扫描次数多次两次内存消耗较低较高(需存储FP-tree)适用场景稀疏数据密集数据实现复杂度简单中等并行能力容易困难选择建议当数据维度高且稀疏时Apriori可能更合适对于密集型数据(如零售交易)FP-Growth通常快10-100倍内存受限环境考虑Apriori高性能服务器可优先FP-Growth在真实项目中我通常会先用小样本测试两种算法性能再决定最终方案。对于特别大的数据集FP-Growth的变种如Parallel FP-Growth可能更合适。