余弦相似度不是推荐系统,仅是向量相似性工具;必须基于用户-物品交互矩阵或嵌入向量计算,直接对原始id编码后计算会因无意义序号导致结果不可解释。

余弦相似度本身不构成推荐系统,它只是计算向量间相似性的工具;直接用它做推荐,必须先有用户-物品交互矩阵或嵌入向量,否则结果毫无意义。
为什么直接对原始用户ID和物品ID算余弦相似度会失败
用户ID(如 user_123)和物品ID(如 movie_456)是离散标识符,没有内在数值结构。对它们做 cosine_similarity 会因编码方式不同返回完全不可解释的值——比如用 LabelEncoder 编码后得到的整数序号,本质是任意排列,不携带偏好信息。
- 错误做法:
cosine_similarity([[1], [2]])→ 得到 1.0,但user_1和user_2可能毫无共同行为 - 正确前提:必须基于行为(如评分、点击次数)或语义(如文本嵌入、图像特征)构造稠密向量
- 典型起点:用户-物品交互矩阵(
scipy.sparse.csr_matrix),每行是用户对所有物品的隐式/显式反馈
如何从交互数据生成可用的用户/物品向量
最轻量且可解释的方式是使用 TF-IDF 或简单归一化后的共现矩阵,而非强行上深度模型。以电影评分为例:
- 用
pandas.crosstab构建user_id×movie_id矩阵,缺失值填 0,评分取平均或二值化(看过=1) - 对每行(用户)做
sklearn.preprocessing.normalize(L2范数归一化),确保余弦相似度只反映方向差异 - 若物品维度太高(如10万部电影),先用
TruncatedSVD(n_components=100)降维,再算相似度——这比硬算全量cosine_similarity快一个数量级
示例关键步骤:
from sklearn.metrics.pairwise import cosine_similarity from sklearn.preprocessing import normalize import numpy as np <h1>假设 user_item_matrix 是 shape (n_users, n_items) 的稀疏矩阵</h1><p>user_vecs = normalize(user_item_matrix, norm='l2', axis=1) user_sim = cosine_similarity(user_vecs) # shape (n_users, n_users)</p>
可视化推荐结果时最容易被忽略的三个细节
画热力图或网络图本身不难,但推荐逻辑是否可信,取决于你怎么定义“相似用户”和“推荐候选”:
- 别用全量
user_sim矩阵找 Top-K 相似用户:应过滤掉交互重叠过少的用户对(例如共同评分数 np.where(common_count >= 3, sim, 0) 再排序 - 物品推荐不能只看相似用户打过分的物品:要排除目标用户已交互过的物品(
mask = ~user_item_matrix[target_user].toarray().astype(bool)) - 可视化时慎用
plt.imshow直接画user_sim:矩阵通常稀疏且非对称(归一化后对称,但原始共现不对称),建议用seaborn.clustermap+ 行列聚类,或抽样 50–100 用户画networkx图,节点大小=活跃度,边粗细=相似度
真正卡住进度的往往不是余弦公式本身,而是向量怎么来、相似用户怎么筛、推荐物品怎么去重——这些地方没约束,可视化再漂亮也是幻觉。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











