使用Surprise库KNNBasic时用户相似度全为0的问题咨询
问题根源
你遇到的问题本质是所有用户的评分全为1,导致基于评分统计量的相似度算法(皮尔逊、cosine、MSD)完全失效:
- 皮尔逊相关系数计算时,用户评分向量的方差为0、协方差也为0,结果直接为0
- MSD算法计算均方误差时,所有评分差都是0,无法区分用户差异
- pearson_baseline会因为分母(方差)为0触发ZeroDivisionError
这类只有正反馈(仅收藏/喜欢,无负反馈)的稀疏数据,不适合用传统基于评分的协同过滤,得换用集合匹配型的相似度算法,比如Jaccard相似度,核心是计算用户间共同收藏的URL比例。
解决方法:基于Jaccard相似度实现用户相似性查找
直接绕开Surprise的评分型KNN,先把用户的收藏数据转换成集合,再计算Jaccard系数:
import pandas as pd # 先把原始数据转换成{用户ID: 收藏URL集合}的字典 user_urls = {} for z in s_data: user_id = z[0] urls = z[1] if urls is not None: user_urls[user_id] = set(urls) # 计算目标用户与其他用户的Jaccard相似度 target_user = 'user1' target_urls = user_urls.get(target_user, set()) similar_users = [] for user_id, urls in user_urls.items(): if user_id == target_user: continue # 计算交集和并集的大小 intersection = len(target_urls & urls) union = len(target_urls | urls) # 处理并集为0的极端情况(两个用户都没收藏任何URL) jaccard = intersection / union if union != 0 else 0.0 similar_users.append((user_id, jaccard)) # 按相似度降序排序 similar_users_sorted = sorted(similar_users, key=lambda x: x[1], reverse=True) print(similar_users_sorted)
额外优化建议
- 如果用户收藏的URL数量极大,直接计算集合交集/并集效率低,可以用MinHash或者SimHash算法来近似计算Jaccard相似度,减少计算量
- 也可以给不同的URL加权(比如根据URL的流行度反加权,越冷门的URL共同收藏越能代表兴趣相似),计算加权Jaccard或者余弦相似度
内容的提问来源于stack exchange,提问作者maston
相关产品推荐
相关产品推荐

