余弦相似度需经中心化与共现过滤才可用于协同过滤;原始稀疏矩阵直接计算会导致误判,商品相似度须用转置矩阵并填充均值,预测时须剔除未评分商品、设相似度阈值并截断结果。

余弦相似度本身不直接支持协同过滤,它只是计算用户或商品向量夹角的工具;真正起作用的是你用它来比较谁和谁——用户之间,还是商品之间。选错维度,推荐结果就完全跑偏。
为什么不能直接对原始评分矩阵算余弦相似度?
原始用户-商品评分矩阵极度稀疏,大量 0 实际代表“未评分”,不是“评分为0”。直接用 cosine_similarity 计算会把大量未交互用户/商品误判为高度相似。
- 必须先做中心化:对每个用户,减去其平均评分(
user_mean),得到偏差向量 - 只在共同评分的商品(非零交集)上计算相似度,跳过全零行/列
- scikit-learn 的
cosine_similarity默认把0当有效值,需手动预处理
怎么用 sklearn.metrics.pairwise.cosine_similarity 正确算商品相似度?
商品协同过滤(Item-CF)要求相似度基于“被相同用户评分过的商品对”,所以输入必须是商品×用户的转置矩阵(即每行是一个商品,每列是一个用户)。
- 先用
pandas.pivot_table构建item_user_matrix,缺失值填np.nan,不是0 - 用
sklearn.impute.SimpleImputer(strategy='mean')按行(商品)填充均值,或更稳妥地:只保留至少被 2 个用户评过分的商品 - 调用前务必用
fillna(0),否则cosine_similarity会报错;但注意这只是占位,实际计算时应 mask 掉未共现部分 - 示例关键片段:
from sklearn.metrics.pairwise import cosine_similarity<br>item_sim = cosine_similarity(item_user_matrix.fillna(0).T) # 注意是 .T
预测评分时,为什么加权和要剔除目标用户没评过分的商品?
公式是:pred_score = user_mean + Σ(sim[i,j] × (rating[j] − item_mean[j])) / Σ|sim[i,j]|,但前提是商品 j 必须在目标用户的历史评分中存在。
- 遍历相似商品列表时,必须检查
user_ratings.get(j)是否非空,否则引入噪声 - 相似度阈值建议设为
0.1 ~ 0.3,太低会拉进无关商品,太高导致邻居不足 - 若某商品无任何相似商品满足阈值,退回到全局平均分或热门商品均值,不要强行插值
- 别忘了最终结果要截断到合理评分范围(如 1–5),
np.clip(pred, 1, 5)
最易被忽略的是数据对齐:用户ID、商品ID在构建矩阵、查相似度、回填预测时必须用同一套索引,pandas 的 .reindex() 和 .loc[] 比直接用 list index 安全得多。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











