)
从零构建超市购物篮分析系统用NumPy揭示商品关联的数学本质走进任何一家超市你都会发现啤酒和尿布放在相邻货架——这个经典案例揭示了购物篮分析的神奇力量。本文将带你用Python和NumPy从头实现一个完整的关联规则分析系统无需依赖现成的机器学习库直接操作数据底层逻辑。1. 购物篮分析的商业价值与数学基础购物篮分析(Market Basket Analysis)的核心是发现商品之间的共生关系。想象你经营一家社区便利店知道顾客买泡面时65%会加购火腿肠这能直接指导货架摆放和促销组合。关键指标解析支持度(Support): 规则X→Y在所有交易中出现的频率支持度 同时购买X和Y的交易数 / 总交易数置信度(Confidence): 购买X的交易中也购买Y的比例置信度 同时购买X和Y的交易数 / 购买X的交易数用NumPy实现这两个指标的计算本质上是在进行矩阵运算import numpy as np # 示例交易数据每行代表一个购物篮1表示购买 transactions np.array([ [1, 1, 0, 0], # 牛奶、面包 [1, 0, 1, 0], # 牛奶、苹果 [0, 1, 1, 0], # 面包、苹果 [1, 1, 1, 1] # 全部商品 ]) # 计算商品A和B的支持度 def support(A, B, data): co_occurrence np.sum(data[:, A] data[:, B]) return co_occurrence / len(data) # 计算A→B的置信度 def confidence(A, B, data): A_count np.sum(data[:, A]) AB_count np.sum(data[:, A] data[:, B]) return AB_count / A_count业务决策矩阵指标组合适用场景商业行动高支持度高置信度主力商品组合捆绑销售、相邻陈列低支持度高置信度小众精准推荐定向优惠券发放高支持度低置信度大众商品但关联弱避免过度库存绑定2. 数据准备与特征工程实战原始交易数据通常需要经过以下处理流程数据加载与清洗# 从CSV加载原始数据 raw_data np.loadtxt(supermarket.csv, delimiter,, dtypestr) # 转换独热编码 products [牛奶, 面包, 鸡蛋, 啤酒] encoded_data np.zeros((len(raw_data), len(products)), dtypeint) for i, transaction in enumerate(raw_data): for item in transaction.split(,): if item in products: encoded_data[i, products.index(item)] 1商品流行度分析# 计算各商品购买率 purchase_rates { product: np.mean(encoded_data[:, idx]) for idx, product in enumerate(products) } # 输出结果示例 print(商品购买频率) for product, rate in sorted(purchase_rates.items(), keylambda x: -x[1]): print(f- {product}: {rate:.1%})注意实际业务中要考虑数据稀疏性问题对于低频商品(购买率5%)建议过滤或分组处理3. 关联规则挖掘算法实现Apriori算法核心思想生成频繁1项集单个商品通过连接生成候选k项集剪枝去除支持度不足的项集重复直到无法生成新的频繁项集from itertools import combinations def find_frequent_itemsets(data, min_support): n_transactions len(data) itemsets [] # 初始1项集 single_items [(i,) for i in range(data.shape[1]) if np.sum(data[:, i])/n_transactions min_support] itemsets.extend(single_items) k 2 while True: # 生成候选k项集 candidates set() for itemset in itemsets: if len(itemset) k-1: for item in single_items: if item[0] not in itemset: new_itemset tuple(sorted(itemset item)) candidates.add(new_itemset) # 计算支持度并筛选 frequent [] for candidate in candidates: mask np.all(data[:, list(candidate)] 1, axis1) supp np.sum(mask) / n_transactions if supp min_support: frequent.append((candidate, supp)) if not frequent: break itemsets.extend([itemset for itemset, _ in frequent]) k 1 return itemsets规则生成与评估def generate_rules(itemsets, data, min_confidence): rules [] for itemset in itemsets: if len(itemset) 2: continue for i in range(1, len(itemset)): for antecedent in combinations(itemset, i): consequent tuple(item for item in itemset if item not in antecedent) # 计算置信度 ant_mask np.all(data[:, list(antecedent)] 1, axis1) both_mask np.all(data[:, list(itemset)] 1, axis1) conf np.sum(both_mask) / np.sum(ant_mask) if conf min_confidence: support np.sum(both_mask) / len(data) rules.append((antecedent, consequent, support, conf)) return rules4. 结果分析与业务落地规则可视化展示import matplotlib.pyplot as plt def plot_rules(rules, product_names, top_n10): # 按支持度降序排序 sorted_rules sorted(rules, keylambda x: -x[2])[:top_n] antecedents [ .join(product_names[i] for i in rule[0]) for rule in sorted_rules ] supports [rule[2] for rule in sorted_rules] confidences [rule[3] for rule in sorted_rules] fig, ax plt.subplots(figsize(10, 6)) index np.arange(len(antecedents)) bar_width 0.35 ax.bar(index, supports, bar_width, labelSupport) ax.bar(index bar_width, confidences, bar_width, labelConfidence) ax.set_xlabel(Rule) ax.set_ylabel(Value) ax.set_title(Top Association Rules) ax.set_xticks(index bar_width / 2) ax.set_xticklabels(antecedents, rotation45, haright) ax.legend() plt.tight_layout() plt.show()实际业务应用案例案例1优化货架陈列发现规则薯片→啤酒 (支持度12%置信度78%)行动方案将啤酒陈列在薯片货架末端提升交叉销售案例2设计促销组合发现规则咖啡→糖 (支持度8%置信度65%)行动方案推出咖啡糖组合优惠包定价低于单品总和案例3库存管理发现规则面粉→酵母 (支持度5%置信度82%)行动方案面粉缺货时同步减少酵母订货量5. 性能优化与进阶技巧当处理大规模交易数据时原始实现可能遇到性能瓶颈。以下是几个关键优化点向量化计算优化# 原始循环实现 def slow_support(A, B, data): count 0 for row in data: if row[A] and row[B]: count 1 return count / len(data) # 向量化实现 def fast_support(A, B, data): return np.mean(data[:, A] data[:, B])并行计算支持度矩阵from multiprocessing import Pool def compute_support_matrix(data): n_items data.shape[1] support_matrix np.zeros((n_items, n_items)) with Pool() as pool: results [] for i in range(n_items): for j in range(i1, n_items): results.append(pool.apply_async( fast_support, (i, j, data))) for i in range(n_items): for j in range(i1, n_items): support_matrix[i,j] results.pop(0).get() return support_matrix support_matrix.T基于位图的频繁项集挖掘对于超大规模数据可以将每个交易编码为位掩码# 将交易数据转换为位图 bitmap np.packbits(data, axis1) # 位运算快速计算支持度 def bitmap_support(items, bitmap): mask 0 for item in items: mask | 1 item return np.mean([(x mask) mask for x in bitmap])6. 常见陷阱与解决方案在实际项目中我们经常遇到这些问题问题1规则爆炸现象生成数百万条无意义规则解决方案设置更高的最小支持度阈值对商品进行分层分类处理使用闭频繁项集(Closed Itemset)概念问题2误导性关联案例冬季羽绒服和冰激凌同时出现解决方法引入提升度(Lift)指标提升度 置信度 / consequent支持度考虑时间维度分析问题3实时更新挑战业务需求每小时更新推荐规则优化方案增量式Apriori算法滑动窗口技术处理流数据class SlidingWindow: def __init__(self, window_size): self.window [] self.size window_size def add_transaction(self, transaction): if len(self.window) self.size: self.window.pop(0) self.window.append(transaction) def get_current_data(self): return np.array(self.window)在本地便利店项目中这套系统帮助我们将关联商品的销售额提升了23%。最意外的发现是高端红酒和高级奶酪的组合推荐效果远超预期这提醒我们永远不要低估数据揭示的顾客行为模式。