Python Surprise库二元0/1评分数据集KNN实现及适配算法选型问题
问题1:稀疏二元评分数据集无需全量补0的KNN优化方案
不需要全量补0即可完成KNN训练,核心优化方案有两类:
- 负采样替代全量补0:每个用户仅采样少量未交互物品作为负样本(0评分),采样数量通常为该用户正样本数量的1~3倍,即可保证模型效果,同时避免数据量指数级膨胀。示例实现代码如下:
import random # 负采样系数:负样本数量为正样本的2倍 neg_sample_ratio = 2 all_item_ids = train['item'].unique() train_filled = [] for uid, group in train.groupby('user'): pos_items = group['item'].tolist() # 加入正样本 for item in pos_items: train_filled.append((uid, item, 1)) # 采样未交互物品作为负样本 neg_candidates = [i for i in all_item_ids if i not in pos_items] sample_cnt = min(len(pos_items)*neg_sample_ratio, len(neg_candidates)) neg_items = random.sample(neg_candidates, sample_cnt) for item in neg_items: train_filled.append((uid, item, 0)) # 生成训练集 train_df = pd.DataFrame(train_filled, columns=['user','item','rating']) train_data = Dataset.load_from_df(train_df, Reader(rating_scale=(0,1))) train_set = train_data.build_full_trainset()
- 自定义稀疏相似度函数:KNN的相似度计算仅需要用户/物品的交互集合,不需要显式存储0值,可以直接调用Surprise内置的
ur(用户已交互物品集合)、ir(物品已被交互用户集合)稀疏结构计算Jaccard、余弦等相似度,完全不需要生成稠密补0矩阵。示例实现代码如下:
from surprise import KNNBasic # 自定义Jaccard相似度,仅用交互集合计算,无需补0 def jaccard_sim(u, v): u_items = set([i for (i, _) in train_set.ur[u]]) v_items = set([i for (i, _) in train_set.ur[v]]) intersection = len(u_items & v_items) union = len(u_items | v_items) return intersection / union if union != 0 else 0 sim_options = { 'name': 'custom', 'user_based': True, 'sim_func': jaccard_sim } algo = KNNBasic(sim_options=sim_options) algo.fit(train_set)
问题2:适配0/1二元评分数据集的Surprise算法
0/1评分属于典型的隐式反馈场景,按适配度从高到低排序如下:
- 首选KNNBaseline:搭配Jaccard或余弦相似度使用,内置的用户/物品基线可以抵消流行度偏差(比如热门物品被大量用户交互的偏置),对稀疏二元交互数据的适配度最高,训练速度快,可解释性强。
- 次选SVDpp:专门优化隐式交互场景的矩阵分解算法,不需要显式处理负样本就能捕捉用户隐式偏好,对二元评分的效果优于普通SVD,仅训练速度略慢于KNN系列。
- 第三选择NMF/CoClustering:NMF的非负约束完美匹配0/1的评分范围,输出的用户/物品向量可解释性强;CoClustering同时对用户和物品做共现聚类,对稀疏二元数据的鲁棒性也很好。
不推荐使用KNNWithZScore、SlopeOne:前者的Z标准化对二元值无意义,后者是针对显式连续评分设计,对二元反馈适配度差。
内容的提问来源于stack exchange,提问作者Masoud Sadrnezhaad
相关产品推荐
相关产品推荐

