如何高效生成Pandas中用户未购买商品的数据结构?
高效生成用户未购买商品的数据结构(基于Pandas)
现有如下格式的Pandas DataFrame:
user_id, item_id 0, 0 0, 1 1, 1 2, 1 2, 2 3, 0每一行代表
user_id对应的用户购买了item_id对应的商品(比如用户0购买了商品0和1)。我们需要生成一个存储用户未购买商品的数据结构,示例的预期结果为:0: 2 1: 0, 2 2: 0 3: 1, 2
你提到的朴素循环实现虽然逻辑简单,但在处理大型DataFrame时会因为逐用户切片查询导致速度极慢:
missing = dict() all_items = set(df['item_id'].unique()) for user in df['user_id'].unique(): user_items = set(df[df['user_id'] == user]['item_id'].values) missing_items = all_items.difference(user_items) missing[user] = missing_items
高效实现方案
下面两种方案都利用Pandas的矢量化操作替代循环,大幅提升处理效率:
方案1:笛卡尔积补集法
通过生成用户-商品的全量组合,再筛选出原始数据中不存在的组合,最后按用户分组:
import pandas as pd # 生成所有用户和所有商品的全量组合 all_users = df['user_id'].unique() all_items = df['item_id'].unique() full_pairs = pd.MultiIndex.from_product([all_users, all_items], names=['user_id', 'item_id']).to_frame(index=False) # 筛选出未购买的用户-商品对 purchased_pairs = df[['user_id', 'item_id']].drop_duplicates() missing_pairs = full_pairs.merge(purchased_pairs, on=['user_id', 'item_id'], how='left', indicator=True) missing_pairs = missing_pairs[missing_pairs['_merge'] == 'left_only'].drop(columns='_merge') # 整理成目标字典格式,可选排序保证和示例结果一致 missing = missing_pairs.groupby('user_id')['item_id'].apply(sorted).to_dict()
方案2:交叉表布尔筛选法
利用交叉表生成用户-商品的购买矩阵,直接筛选未购买的商品列:
# 生成用户×商品的购买状态矩阵(1表示已购买,0表示未购买) purchase_matrix = pd.crosstab(df['user_id'], df['item_id']) # 对每个用户筛选出未购买的商品,转成字典 missing = purchase_matrix.apply(lambda row: purchase_matrix.columns[row == 0].tolist(), axis=1).to_dict() # 可选排序 missing = {user: sorted(items) for user, items in missing.items()}
效率说明
- 朴素循环的核心问题是多次重复切片查询DataFrame,时间复杂度随用户数和商品数线性增长,大型数据集下性能极差
- 矢量化方案依托Pandas底层的C级运算优化,避免了循环中的重复IO和查询操作,处理百万级用户-商品数据时,效率能提升数十倍甚至上百倍
内容的提问来源于stack exchange,提问作者Ach113
相关产品推荐
相关产品推荐

