数据集商品项购买频次相关性分析求助:含大数量级及行项不均问题
商品购买频次相关性分析全解
Hey there! 看起来你已经在商品购买关联分析的路上走了不少路了——拆分订单、清洗商品名称都搞定了,现在卡在了相关性分析的核心步骤上对吧?我来帮你逐个理清这些问题:
1. 如何有效展示商品项之间的购买频次相关性?是否需要构建0-1矩阵?
首先给你一个明确的答案:构建0-1矩阵是这类关联分析的标准基础操作,它把订单里“是否购买某商品”的状态量化,是后续计算关联规则(比如Apriori)、相关性系数的前提。
除了0-1矩阵本身,展示相关性还有几个更直观的方式:
- 热力图:用颜色深浅直接呈现商品间的共现频次或相关系数,一眼就能看到哪些商品绑定得最紧
- 关联规则可视化:比如用节点图展示「买Hamburger的人同时买Soda的概率」这类置信度数据
- 共现频次矩阵:直接统计每对商品一起出现在订单里的次数,简单直接
所以0-1矩阵是必要的中间环节,后续所有分析都得基于它展开。
2. 百万行级别数据集构建0-1矩阵的最优实现方法
直接用循环处理百万行数据绝对是噩梦——慢到离谱还容易内存溢出。推荐你用向量化操作和专门的数据分析库来优化,这里给你两个实用方案:
方案一:用pandas的str.get_dummies(简洁高效)
先把每行的商品合并成一个用分隔符连接的字符串,然后一键生成0-1矩阵:
# 先把清洗后的Item列合并成每行的商品列表(过滤掉None) df['Items'] = df[['Item0', 'Item1', 'Item2']].apply( lambda x: ' '.join([i for i in x if i is not None]), axis=1 ) # 一键生成0-1矩阵,sep是你用的分隔符(这里用空格) one_hot_matrix = df['Items'].str.get_dummies(sep=' ')
注意:如果你的商品名里有空格(比如"Ice Cream"),得先把空格换成其他字符(比如下划线),不然会被拆成两个词。
方案二:用mlxtend的TransactionEncoder(专为关联分析设计)
mlxtend是机器学习扩展工具库,里面的TransactionEncoder就是为订单-商品这种格式量身打造的,处理大数据集的效率比纯pandas还高:
from mlxtend.preprocessing import TransactionEncoder import pandas as pd # 把每行的商品转换成列表(过滤None) transactions = df[['Item0', 'Item1', 'Item2']].apply( lambda x: [i for i in x if i is not None], axis=1 ).tolist() # 初始化编码器并生成0-1矩阵 te = TransactionEncoder() encoded_data = te.fit_transform(transactions) one_hot_matrix = pd.DataFrame(encoded_data, columns=te.columns_)
这个方法不用操心商品名的分隔符问题,而且底层做了优化,百万行数据跑起来也很顺畅。
额外性能优化小贴士
- 把0-1矩阵的 dtype 设为
uint8:因为只存0和1,uint8比默认的bool类型更省内存 - 先过滤低频商品:比如把只出现过1-2次的商品删掉,减少矩阵维度,提升计算速度
- 分批次处理:如果内存不够,就把数据集分成若干小批次处理,最后再合并结果
3. 行内商品数量不均是否会导致相关性结果偏差?
确实会有影响,但选对指标就能规避这个问题:
为什么会有偏差?
举个例子:一个包含3种商品的订单会产生3对商品共现,而2种商品的订单只产生1对。如果直接用共现次数计算相关性,那些经常出现在多商品订单里的商品,相关性会被高估——因为它们贡献了更多的共现对。
怎么解决?
- 用关联分析的核心指标(支持度/置信度)代替普通相关性:
- 支持度:商品A+B共现的订单数 ÷ 总订单数,这个指标完全不受订单内商品数量影响
- 置信度:商品A+B共现的订单数 ÷ 商品A出现的订单数,衡量的是“买A的人同时买B”的概率,也不受订单商品数干扰
- 用余弦相似度代替皮尔逊相关系数:
皮尔逊相关会受向量长度(订单内商品数)影响,而余弦相似度只关注向量的方向——也就是商品共同出现的比例,完美规避订单商品数的干扰 - 给订单内的商品加权:把每个商品的权重设为
1/订单内商品数,这样每个订单对共现的总贡献是1,而不是商品数量,避免多商品订单过度加权。代码示例:
def assign_weight(row): valid_items = [i for i in row if i is not None] if not valid_items: return pd.Series() weight = 1 / len(valid_items) return pd.Series({item: weight for item in valid_items}) weighted_matrix = df[['Item0', 'Item1', 'Item2']].apply(assign_weight, axis=1).fillna(0)
内容的提问来源于stack exchange,提问作者Dansekongen
相关产品推荐
相关产品推荐

