Langchain系列文章目录
01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
PyTorch系列文章目录
Python系列文章目录
机器学习系列文章目录
01-什么是机器学习?从零基础到自动驾驶案例全解析
02-从过拟合到强化学习:机器学习核心知识全解析
03-从零精通机器学习:线性回归入门
04-逻辑回归 vs. 线性回归:一文搞懂两者的区别与应用
05-决策树算法全解析:从零基础到Titanic实战,一文搞定机器学习经典模型
06-集成学习与随机森林:从理论到实践的全面解析
07-支持向量机(SVM):从入门到精通的机器学习利器
08-【机器学习】KNN算法入门:从零到电影推荐实战
09-【机器学习】朴素贝叶斯入门:从零到垃圾邮件过滤实战
10-【机器学习】聚类算法全解析:K-Means、层次聚类、DBSCAN在市场细分的应用
11-【机器学习】降维与特征选择全攻略:PCA、LDA与特征选择方法详解
12-【机器学习】手把手教你构建神经网络:从零到手写数字识别实战
13-【机器学习】从零开始学习卷积神经网络(CNN):原理、架构与应用
14-【机器学习】RNN与LSTM全攻略:解锁序列数据的秘密
15-【机器学习】GAN从入门到实战:手把手教你实现生成对抗网络
16-【机器学习】强化学习入门:从零掌握 Agent 到 DQN 核心概念与 Gym 实战
17-【机器学习】AUC、F1分数不再迷茫:图解Scikit-Learn模型评估与选择核心技巧
18-【机器学习】Day 18: 告别盲猜!网格/随机/贝叶斯搜索带你精通超参数调优
19-【机器学习】从零精通特征工程:Kaggle金牌选手都在用的核心技术
20-【机器学习】模型性能差?90%是因为数据没洗干净!(缺失值/异常值/不平衡处理)
21-【机器学习】保姆级教程:7步带你从0到1完成泰坦尼克号生还预测项目
22-【机器学习】框架三巨头:Scikit-Learn vs TensorFlow/Keras vs PyTorch 全方位对比与实战
23-【机器学习】揭秘迁移学习:如何用 ResNet 和 BERT 加速你的 AI 项目?
24-【机器学习】NLP核心技术详解:用Scikit-learn、Gensim和Hugging Face玩转文本处理 (Day 24)
25-【机器学习】解密计算机视觉:CNN、目标检测与图像识别核心技术(Day 25)
26-【机器学习】万字长文:深入剖析推荐系统核心算法 (协同过滤/内容/SVD) 与Python实战
文章目录
前言
在信息爆炸的时代,我们每天都面临着海量的选择:看什么电影、听什么音乐、买什么商品、读什么新闻?推荐系统(Recommender System)应运而生,它像一位懂你的智能助手,通过分析你的历史行为和偏好,为你精准推送可能感兴趣的内容,极大地提升了用户体验和平台效率。从电商平台的“猜你喜欢”到视频网站的个性化推送,推荐系统已无处不在。
本篇文章是【机器学习】系列专栏的第 26 篇,我们将深入探索推荐系统的核心——构建个性化推荐引擎的算法。无论你是刚接触推荐系统的小白,还是希望深化理解的进阶者,本文都将带你从基础概念出发,逐步掌握协同过滤、基于内容推荐等核心算法的原理与实践,了解如何评估推荐效果,并探讨冷启动等实际挑战。我们还将通过 Python 代码实战一个简单的推荐器,并尝试分析知名应用背后的推荐策略。准备好了吗?让我们一起揭开用户兴趣的奥秘!
一、推荐系统概述:不止一种“猜你喜欢”
推荐系统的核心目标是连接用户和物品(Item,可以是商品、电影、文章等),预测用户对未知物品的偏好程度。根据实现原理和利用的数据不同,推荐系统主要可以分为以下几类:
1.1 推荐系统主要类型
1.1.1 协同过滤推荐 (Collaborative Filtering, CF)
这是目前应用最广泛的推荐技术之一。其核心思想是“物以类聚,人以群分”。它不依赖物品本身的内容信息,而是通过分析大量用户的历史行为数据(如评分、购买、点击等)来发现用户或物品之间的相似性,并据此进行推荐。
- 优点: 不需要物品的内容信息,能够发现用户潜在的、意想不到的兴趣点(惊喜度高)。
- 缺点: 存在冷启动问题(新用户、新物品难以推荐),数据稀疏性问题(用户行为数据通常非常稀疏)。
1.1.2 基于内容的推荐 (Content-Based Recommendation)
这种方法的核心是“为你推荐与你过去喜欢的物品相似的物品”。它基于物品自身的内容属性(如电影的类型、导演、演员,文章的关键词、主题)和用户的历史偏好记录(用户喜欢过哪些属性的物品)来进行推荐。
- 优点: 对新物品友好(只要有内容信息就能推荐),用户偏好解释性强。
- 缺点: 难以发现用户潜在兴趣(推荐结果容易局限于用户已知领域),需要良好的物品内容特征提取。
1.1.3 混合推荐 (Hybrid Recommendation)
混合推荐系统结合了协同过滤和基于内容推荐等多种方法的优点,试图克服单一方法的缺点,以达到更好的推荐效果。常见的混合策略包括:
- 加权型: 将多种推荐算法的预测结果加权组合。
- 切换型: 根据不同情况(如用户活跃度、物品信息完善度)选择不同的推荐算法。
- 特征组合: 将内容特征融入协同过滤模型中。
- 层叠型: 用一种算法产生候选集,再用另一种算法进行精排。
二、协同过滤详解:发现群体智慧的力量
协同过滤是推荐系统中最经典、最核心的技术之一。它主要分为基于记忆的(Memory-based)方法和基于模型的(Model-based)方法。
2.1 基于记忆的协同过滤
基于记忆的方法直接使用用户-物品交互矩阵中的数据来计算用户或物品间的相似度。
2.1.1 基于用户的协同过滤 (User-Based Collaborative Filtering, UserCF)
核心思想:给用户 U 推荐那些与他兴趣相似的其他用户 V 所喜欢的,而用户 U 尚未接触过的物品。
工作流程:
-
找到相似用户: 计算目标用户 U 与其他所有用户 V 之间的相似度。常用的相似度计算方法包括:
- 皮尔逊相关系数 (Pearson Correlation Coefficient): 度量两个变量线性相关程度。对于用户 U 和 V,计算公式为:
S i m ( U , V ) = ∑ i ∈ I U V ( R U i − R ˉ U ) ( R V i − R ˉ V ) ∑ i ∈ I U V ( R U i − R ˉ U ) 2 ∑ i ∈ I U V ( R V i − R ˉ V ) 2 Sim(U, V) = \frac{\sum_{i \in I_{UV}}(R_{Ui} - \bar{R}_U)(R_{Vi} - \bar{R}_V)}{\sqrt{\sum_{i \in I_{UV}}(R_{Ui} - \bar{R}_U)^2} \sqrt{\sum_{i \in I_{UV}}(R_{Vi} - \bar{R}_V)^2}} Sim(U,V)=∑i∈IUV(RUi−RˉU)2∑i∈IUV(RVi−RˉV)2∑i∈IUV(RUi−RˉU)(RVi−RˉV)
其中, I U V I_{UV} IUV 是用户 U 和 V 共同评分过的物品集合, R U i R_{Ui} RUi 是用户 U 对物品 i 的评分, R ˉ U \bar{R}_U RˉU 是用户 U 的平均评分。皮尔逊系数对评分尺度不敏感。 - 余弦相似度 (Cosine Similarity): 将用户评分向量视为多维空间中的向量,计算向量间的夹角余弦值。
S i m ( U , V ) = cos ( U ⃗ , V ⃗ ) = U ⃗ ⋅ V ⃗ ∣ ∣ U ⃗ ∣ ∣ ⋅ ∣ ∣ V ⃗ ∣ ∣ = ∑ i ∈ I U V R U i R V i ∑ i ∈ I U R U i 2 ∑ i ∈ I V R V i 2 Sim(U, V) = \cos(\vec{U}, \vec{V}) = \frac{\vec{U} \cdot \vec{V}}{||\vec{U}|| \cdot ||\vec{V}||} = \frac{\sum_{i \in I_{UV}} R_{Ui} R_{Vi}}{\sqrt{\sum_{i \in I_{U}} R_{Ui}^2} \sqrt{\sum_{i \in I_{V}} R_{Vi}^2}} Sim(U,V)=cos(U,V)=∣∣U∣∣⋅∣∣V∣∣U⋅V=∑i∈IURUi2∑i∈IVRVi2∑i∈IUVRUiRVi
这里 I U I_U IU 和 I V I_V IV 分别是用户 U 和 V 评分过的所有物品集合。余弦相似度更关注向量方向而非绝对值。 - Jaccard 相似系数 (Jaccard Index): 主要用于处理只有行为(如点击、购买)没有评分的场景,衡量两个用户交互过的物品集合的交集与并集之比。
S i m ( U , V ) = ∣ N ( U ) ∩ N ( V ) ∣ ∣ N ( U ) ∪ N ( V ) ∣ Sim(U, V) = \frac{|N(U) \cap N(V)|}{|N(U) \cup N(V)|} Sim(U,V)=∣N(U)∪N(V)∣∣N(U)∩N(V)∣
其中 N ( U ) N(U) N(U) 是用户 U 交互过的物品集合。
- 皮尔逊相关系数 (Pearson Correlation Coefficient): 度量两个变量线性相关程度。对于用户 U 和 V,计算公式为:
-
生成推荐: 找到与用户 U 最相似的 K 个用户(Top-K Neighbors),然后预测用户 U 对他未交互过的物品 j 的评分(或偏好度):
P U j = R ˉ U + ∑ V ∈ N e i g h b o r s ( U ) S i m ( U , V ) × ( R V j − R ˉ V ) ∑ V ∈ N e i g h b o r s ( U ) ∣ S i m ( U , V ) ∣ P_{Uj} = \bar{R}_U + \frac{\sum_{V \in Neighbors(U)} Sim(U, V) \times (R_{Vj} - \bar{R}_V)}{\sum_{V \in Neighbors(U)} |Sim(U, V)|} PUj=RˉU+∑V∈Neighbors(U)∣Sim(U,V)∣∑V∈Neighbors(U)Sim(U,V)×(RVj−RˉV)
或者一种更简单的形式:
P U j = ∑ V ∈ N e i g h b o r s ( U ) S i m ( U , V ) × R V j ∑ V ∈ N e i g h b o r s ( U ) ∣ S i m ( U , V ) ∣ P_{Uj} = \frac{\sum_{V \in Neighbors(U)} Sim(U, V) \times R_{Vj}}{\sum_{V \in Neighbors(U)} |Sim(U, V)|} PUj=∑V∈Neighbors(U)∣Sim(U,V)∣∑V∈Neighbors(U)Sim(U,V)×RVj
最后将预测评分最高的若干物品推荐给用户 U。
优点: 能够推荐不同领域的新物品,发现用户的潜在兴趣。
缺点: 用户数量通常远大于物品数量,计算用户相似度矩阵开销大;用户相似度会随着新用户加入或用户兴趣变化而改变,需要频繁更新;在用户行为稀疏时效果不佳。
2.1.2 基于物品的协同过滤 (Item-Based Collaborative Filtering, ItemCF)
核心思想: 给用户 U 推荐那些与他过去喜欢的物品相似的物品。
工作流程:
-
计算物品相似度: 计算物品 i 与物品 j 之间的相似度。这通常基于同时喜欢(评分/交互)这两个物品的用户群体。
- 调整余弦相似度 (Adjusted Cosine Similarity): 为了消除用户评分尺度的影响,计算物品相似度时,先将每个用户的评分减去该用户的平均分。
S i m ( i , j ) = ∑ U ∈ U i j ( R U i − R ˉ U ) ( R U j − R ˉ U ) ∑ U ∈ U i j ( R U i − R ˉ U ) 2 ∑ U ∈ U i j ( R U j − R ˉ U ) 2 Sim(i, j) = \frac{\sum_{U \in U_{ij}}(R_{Ui} - \bar{R}_U)(R_{Uj} - \bar{R}_U)}{\sqrt{\sum_{U \in U_{ij}}(R_{Ui} - \bar{R}_U)^2} \sqrt{\sum_{U \in U_{ij}}(R_{Uj} - \bar{R}_U)^2}} Sim(i,j)=∑U∈Uij(RUi−RˉU)2∑U∈Uij(RUj−RˉU)2∑U∈Uij(RUi−RˉU)(RUj−RˉU)
其中, U i j U_{ij} Uij 是同时对物品 i 和 j 评分过的用户集合。 - 余弦相似度: 也可以直接使用物品被评分的向量计算余弦相似度。
S i m ( i , j ) = cos ( I ⃗ i , I ⃗ j ) = I ⃗ i ⋅ I ⃗ j ∣ ∣ I ⃗ i ∣ ∣ ⋅ ∣ ∣ I ⃗ j ∣ ∣ = ∑ U ∈ U i j R U i R U j ∑ U ∈ U i R U i 2 ∑ U ∈ U j R U j 2 Sim(i, j) = \cos(\vec{I}_i, \vec{I}_j) = \frac{\vec{I}_i \cdot \vec{I}_j}{||\vec{I}_i|| \cdot ||\vec{I}_j||} = \frac{\sum_{U \in U_{ij}} R_{Ui} R_{Uj}}{\sqrt{\sum_{U \in U_i} R_{Ui}^2} \sqrt{\sum_{U \in U_j} R_{Uj}^2}} Sim(i,j)=cos(Ii,Ij)=∣∣Ii∣∣⋅∣∣Ij∣∣Ii⋅Ij=∑U∈UiRUi2∑U∈UjRUj2∑U∈UijRUiRUj
其中 U i U_i Ui 和 U j U_j Uj 分别是对物品 i 和 j 评过分的用户集合。
- 调整余弦相似度 (Adjusted Cosine Similarity): 为了消除用户评分尺度的影响,计算物品相似度时,先将每个用户的评分减去该用户的平均分。
-
生成推荐: 找到用户 U 喜欢(评过高分或交互过)的物品集合 N(U),然后预测用户 U 对他未交互过的物品 j 的评分(或偏好度):
P U j = ∑ i ∈ N ( U ) ∩ N e i g h b o r s ( j ) S i m ( i , j ) × R U i ∑ i ∈ N ( U ) ∩ N e i g h b o r s ( j ) ∣ S i m ( i , j ) ∣ P_{Uj} = \frac{\sum_{i \in N(U) \cap Neighbors(j)} Sim(i, j) \times R_{Ui}}{\sum_{i \in N(U) \cap Neighbors(j)} |Sim(i, j)|} PUj=∑i∈N(U)∩Neighbors(j)∣Sim(i,j)∣∑i∈N(U)∩Neighbors(j)Sim(i,j)×RUi
其中, N e i g h b o r s ( j ) Neighbors(j) Neighbors(j) 是与物品 j 最相似的 K 个物品集合, R U i R_{Ui} RUi 是用户 U 对物品 i 的评分。将预测评分最高的若干物品推荐给用户 U。
优点: 物品数量通常相对稳定且少于用户数量,物品相似度矩阵计算相对容易且可以离线计算,更新频率较低;推荐结果解释性较好(因为你喜欢A,所以给你推荐相似的B);在物品数量远小于用户数量的场景下性能较好。
缺点: 难以挖掘长尾物品(热门物品更容易出现在相似邻居中);推荐结果相对单一,惊喜度不如 UserCF。
场景选择: UserCF 更适合新闻推荐等用户兴趣变化快、物品时效性强的场景;ItemCF 更适合商品推荐、电影推荐等用户兴趣相对稳定、物品数量相对较少的场景。
2.2 基于模型的协同过滤
基于模型的方法试图从用户-物品交互数据中学习一个潜在的模型,用这个模型来预测用户对未交互物品的评分。其中,矩阵分解(Matrix Factorization)是最常用的一类方法。
2.2.1 隐语义模型 / 矩阵分解 (Latent Factor Model / Matrix Factorization)
核心思想: 假设存在一个低维度的隐语义空间(Latent Factor Space),每个用户和每个物品都可以表示为这个空间中的一个向量。用户 U 对物品 i 的评分
R
U
i
R_{Ui}
RUi 可以通过用户向量
p
⃗
U
\vec{p}_U
pU 和物品向量
q
⃗
i
\vec{q}_i
qi 的点积来近似估计:
R
^
U
i
≈
p
⃗
U
T
q
⃗
i
=
∑
k
=
1
K
p
U
k
q
i
k
\hat{R}_{Ui} \approx \vec{p}_U^T \vec{q}_i = \sum_{k=1}^{K} p_{Uk} q_{ik}
R^Ui≈pUTqi=k=1∑KpUkqik
其中 K 是隐语义空间的维度(一个超参数,远小于用户数和物品数)。
p
⃗
U
\vec{p}_U
pU 表示用户的偏好在各个隐因子上的强度,
q
⃗
i
\vec{q}_i
qi 表示物品在各个隐因子上的分布。这些隐因子可能是无法直观解释的,例如代表电影的“喜剧程度”、“动作程度”或者用户的“偏爱文艺片程度”等。
模型学习: 目标是找到最优的用户向量 P (所有用户向量组成的矩阵) 和物品向量 Q (所有物品向量组成的矩阵),使得预测评分
R
^
U
i
\hat{R}_{Ui}
R^Ui 与真实评分
R
U
i
R_{Ui}
RUi 之间的误差最小。通常通过最小化带正则化的平方损失函数来实现:
min
P
,
Q
∑
(
U
,
i
)
∈
O
b
s
e
r
v
e
d
(
R
U
i
−
p
⃗
U
T
q
⃗
i
)
2
+
λ
(
∣
∣
p
⃗
U
∣
∣
2
+
∣
∣
q
⃗
i
∣
∣
2
)
\min_{P, Q} \sum_{(U, i) \in Observed} (R_{Ui} - \vec{p}_U^T \vec{q}_i)^2 + \lambda (||\vec{p}_U||^2 + ||\vec{q}_i||^2)
P,Qmin(U,i)∈Observed∑(RUi−pUTqi)2+λ(∣∣pU∣∣2+∣∣qi∣∣2)
其中 Observed
表示所有已知的用户-物品评分记录。正则化项
λ
(
∣
∣
p
⃗
U
∣
∣
2
+
∣
∣
q
⃗
i
∣
∣
2
)
\lambda (||\vec{p}_U||^2 + ||\vec{q}_i||^2)
λ(∣∣pU∣∣2+∣∣qi∣∣2) 用于防止过拟合,
λ
\lambda
λ 是正则化系数。
常用的优化算法包括:
- 随机梯度下降 (Stochastic Gradient Descent, SGD): 对每个已知的评分样本
(
U
,
i
)
(U, i)
(U,i),按照梯度的反方向更新
p
⃗
U
\vec{p}_U
pU 和
q
⃗
i
\vec{q}_i
qi。
- 计算误差: e U i = R U i − p ⃗ U T q ⃗ i e_{Ui} = R_{Ui} - \vec{p}_U^T \vec{q}_i eUi=RUi−pUTqi
- 更新规则:
p ⃗ U ← p ⃗ U + γ ( e U i q ⃗ i − λ p ⃗ U ) \vec{p}_U \leftarrow \vec{p}_U + \gamma (e_{Ui} \vec{q}_i - \lambda \vec{p}_U) pU←pU+γ(eUiqi−λpU)
q ⃗ i ← q ⃗ i + γ ( e U i p ⃗ U − λ q ⃗ i ) \vec{q}_i \leftarrow \vec{q}_i + \gamma (e_{Ui} \vec{p}_U - \lambda \vec{q}_i) qi←qi+γ(eUipU−λqi)
其中 γ \gamma γ 是学习率。
- 交替最小二乘 (Alternating Least Squares, ALS): 固定用户向量 P,优化物品向量 Q;然后固定 Q,优化 P,交替进行直至收敛。这种方法适合并行化处理。
奇异值分解 (Singular Value Decomposition, SVD): 原始的 SVD 要求矩阵是稠密的,不能直接用于稀疏的评分矩阵。实际应用中常用的是 SVD 的变种或受其启发的矩阵分解方法,如上面描述的基于 SGD 或 ALS 优化的模型。有时也会用 FunkSVD、SVD++ 等包含偏置项(用户偏置、物品偏置、全局偏置)的模型来提高预测精度:
R
^
U
i
=
μ
+
b
U
+
b
i
+
p
⃗
U
T
q
⃗
i
\hat{R}_{Ui} = \mu + b_U + b_i + \vec{p}_U^T \vec{q}_i
R^Ui=μ+bU+bi+pUTqi
其中
μ
\mu
μ 是全局平均评分,
b
U
b_U
bU 是用户 U 的评分偏置(有的用户倾向于打高分),
b
i
b_i
bi 是物品 i 的评分偏置(有的物品普遍评分较高)。
优点: 能够处理数据稀疏性问题;模型泛化能力强;可以学习到潜在的关联;预测精度通常优于基于记忆的方法。
缺点: 模型训练过程计算量较大;学习到的隐因子缺乏直观解释性。
三、基于内容的推荐:懂你所爱
基于内容的推荐不依赖其他用户的行为,而是专注于用户自身的历史偏好和物品的内容特征。
3.1 原理与流程
核心思想: 基于用户过去喜欢(例如,评分高、点击、购买)的物品的内容特征,构建用户的偏好画像(User Profile),然后推荐与该画像匹配的物品。
工作流程:
-
物品特征提取 (Item Representation): 对物品进行内容分析,提取关键特征。
- 电影: 类型、导演、演员、关键词、剧情简介等。
- 新闻文章: 关键词、主题分类(TF-IDF、LDA)、实体、来源等。
- 商品: 品牌、类别、标签、描述文本、价格等。
将这些特征表示成向量形式(例如,使用 TF-IDF 向量表示文本特征)。
-
用户偏好建模 (User Profile Learning): 根据用户历史交互过的物品的特征,构建用户的偏好画像向量。
- 简单方法:将用户喜欢过的所有物品的特征向量进行加权平均(例如,用评分作为权重)。
- 复杂方法:训练一个分类器(如逻辑回归、SVM),预测用户是否会喜欢某个特定特征的物品。
-
匹配与推荐 (Matching & Recommendation): 计算用户画像向量与候选物品特征向量之间的相似度(常用余弦相似度),将相似度最高的 Top-K 物品推荐给用户。
S c o r e ( U s e r , I t e m ) = S i m ( P r o f i l e ⃗ U s e r , F e a t u r e ⃗ I t e m ) Score(User, Item) = Sim(\vec{Profile}_{User}, \vec{Feature}_{Item}) Score(User,Item)=Sim(ProfileUser,FeatureItem)
优点:
- 用户独立性: 用户之间的推荐互不影响。
- 可解释性: 可以向用户解释推荐原因(例如,“因为你喜欢科幻电影,所以为你推荐这部”)。
- 新物品友好: 只要物品有内容描述,就能立即进行推荐,没有冷启动问题。
- 无需大量用户数据: 即使只有一个用户的行为数据也可以进行推荐。
缺点:
- 特征工程依赖: 推荐效果严重依赖于物品特征提取的质量。
- 过度专业化/惊喜度低: 推荐结果往往与用户历史兴趣高度相似,难以发现新的兴趣领域。
- 新用户冷启动: 对于没有任何历史行为的新用户,无法建立准确的用户画像(需要一些初始信息或默认推荐)。
四、评估推荐系统:好不好,量化说了算
如何衡量一个推荐系统的好坏?我们需要一套客观的评估指标。评估通常分为离线评估、在线评估(A/B 测试)和用户调研。这里我们主要介绍常用的离线评估指标,它们基于已有的用户行为数据集进行计算。
假设我们为用户生成了一个包含 N 个物品的推荐列表。
4.1 常用评估指标
4.1.1 准确率 (Precision@K) 和 召回率 (Recall@K)
这是最常用的 Top-K 推荐评估指标。
- Precision@K: 推荐列表中 K 个物品,有多少是用户真正感兴趣(例如,实际点击/购买/评分高)的?
P r e c i s i o n @ K = ∣ R e c o m m e n d e d I t e m s @ K ∩ R e l e v a n t I t e m s ∣ ∣ R e c o m m e n d e d I t e m s @ K ∣ = 预测对的数量 推荐列表长度 K Precision@K = \frac{|RecommendedItems@K \cap RelevantItems|}{|RecommendedItems@K|} = \frac{预测对的数量}{推荐列表长度 K} Precision@K=∣RecommendedItems@K∣∣RecommendedItems@K∩RelevantItems∣=推荐列表长度K预测对的数量 - Recall@K: 用户真正感兴趣的所有物品中,有多少被包含在了推荐列表 K 中?
R e c a l l @ K = ∣ R e c o m m e n d e d I t e m s @ K ∩ R e l e v a n t I t e m s ∣ ∣ R e l e v a n t I t e m s ∣ = 预测对的数量 用户实际喜欢的总数 Recall@K = \frac{|RecommendedItems@K \cap RelevantItems|}{|RelevantItems|} = \frac{预测对的数量}{用户实际喜欢的总数} Recall@K=∣RelevantItems∣∣RecommendedItems@K∩RelevantItems∣=用户实际喜欢的总数预测对的数量
Precision 关注推荐结果的准确性,Recall 关注推荐结果的覆盖率/查全率。通常两者是相互制约的。
4.1.2 平均准确率均值 (Mean Average Precision, MAP)
MAP 考虑了推荐列表中相关物品的排序位置。对于单个用户,Average Precision (AP) 计算如下:
A
P
@
K
=
1
m
∑
k
=
1
K
(
P
r
e
c
i
s
i
o
n
@
k
×
r
e
l
(
k
)
)
AP@K = \frac{1}{m} \sum_{k=1}^{K} (Precision@k \times rel(k))
AP@K=m1k=1∑K(Precision@k×rel(k))
其中,m 是用户实际感兴趣物品的总数,rel(k)
是一个指示函数,如果第 k 个推荐物品是相关的,则为 1,否则为 0。AP 越高,表示相关的物品越排在推荐列表的前面。
MAP 则是对所有用户的 AP 值取平均:
M
A
P
=
1
∣
U
s
e
r
s
∣
∑
u
∈
U
s
e
r
s
A
P
u
MAP = \frac{1}{|Users|} \sum_{u \in Users} AP_u
MAP=∣Users∣1u∈Users∑APu
4.1.3 归一化折损累计增益 (Normalized Discounted Cumulative Gain, NDCG@K)
NDCG 不仅考虑了物品是否相关,还考虑了相关性的等级(例如,评分 1-5 分)。
- Cumulative Gain (CG@K): 推荐列表前 K 个物品的相关性得分之和。
C G @ K = ∑ i = 1 K r e l i CG@K = \sum_{i=1}^{K} rel_i CG@K=i=1∑Kreli
其中 r e l i rel_i reli 是第 i 个推荐物品的相关性得分。 - Discounted Cumulative Gain (DCG@K): 考虑位置因素,排名越靠前的物品贡献越大。
D C G @ K = ∑ i = 1 K r e l i log 2 ( i + 1 ) 或者 D C G @ K = r e l 1 + ∑ i = 2 K r e l i log 2 ( i ) DCG@K = \sum_{i=1}^{K} \frac{rel_i}{\log_2(i+1)} \quad \text{或者} \quad DCG@K = rel_1 + \sum_{i=2}^{K} \frac{rel_i}{\log_2(i)} DCG@K=i=1∑Klog2(i+1)reli或者DCG@K=rel1+i=2∑Klog2(i)reli - Ideal DCG (IDCG@K): 理想情况下的 DCG,即把用户所有相关物品按相关性从高到低排序,计算前 K 个的 DCG 值。
- Normalized DCG (NDCG@K): 将 DCG 归一化,使其值介于 0 到 1 之间。
N D C G @ K = D C G @ K I D C G @ K NDCG@K = \frac{DCG@K}{IDCG@K} NDCG@K=IDCG@KDCG@K
NDCG 是一个综合考虑排序和相关性等级的常用指标。
4.1.4 其他指标
- 覆盖率 (Coverage): 推荐系统能够推荐出来的物品占总物品库的比例。高覆盖率表示推荐系统能发掘更多长尾物品。
- 多样性 (Diversity): 推荐列表中物品之间的差异性。
- 新颖性/惊喜度 (Novelty/Serendipity): 推荐给用户的物品是用户之前不知道但可能感兴趣的程度。
下表总结了常用评估指标的关注点:
指标 | 关注点 |
---|---|
Precision@K | 推荐准确性 (Top-K 中有多少是对的) |
Recall@K | 覆盖率/查全率 (对的物品有多少被推荐出来了) |
MAP | 排序质量 (对的物品是否排在前面,考虑所有相关物品) |
NDCG@K | 排序质量 & 相关性等级 (对的物品是否排在前面,且考虑得分高低) |
Coverage | 推荐广度 (能推荐多少不同的物品) |
Diversity | 推荐列表内部差异性 |
Novelty | 推荐新颖程度 (是否是用户不知道的) |
注意: 离线评估结果与在线实际效果(如点击率、转化率)可能存在差异,最终效果需以在线 A/B 测试为准。
五、冷启动问题:新来的怎么办?
冷启动问题是推荐系统,特别是协同过滤面临的一大挑战。它主要分为三类:
5.1 用户冷启动 (User Cold Start)
新用户刚注册,没有任何行为数据,系统不知道其偏好,难以进行个性化推荐。
解决方案:
- 提供非个性化推荐: 推荐热门物品、高评分物品。
- 利用注册信息: 基于用户的(可选)注册信息(如年龄、性别、地理位置)进行粗略推荐。
- 引导用户提供偏好: 在用户注册初期,引导用户选择感兴趣的标签、类别或对一些代表性物品进行评分。
- 结合内容推荐: 如果有用户属性信息,可以先用基于内容的思路推荐。
5.2 物品冷启动 (Item Cold Start)
新物品刚上架,没有用户对其产生交互行为,系统无法判断哪些用户可能喜欢它,难以将其推荐出去(尤其对于协同过滤)。
解决方案:
- 利用物品内容信息: 对于新物品,优先使用基于内容的推荐方法,将其推荐给对相似内容感兴趣的用户。
- 随机或推广: 将新物品小范围随机展示给部分用户,或进行一定的推广,以收集初始交互数据。
- 专家或编辑标注: 请专家或编辑为新物品打上标签或初始评分。
5.3 系统冷启动 (System Cold Start)
新开发的推荐系统,没有任何用户行为数据积累,无法运行上述任何推荐算法。
解决方案:
- 从非个性化开始: 先上线热门推荐等简单策略。
- 引入外部数据: 如果可能,引入其他来源的数据作为初始启动。
- 快速积累数据: 尽快上线系统,收集用户交互数据。
六、实战:用 Python 构建简单的电影推荐器 (ItemCF)
下面我们使用经典的 MovieLens 1M 数据集,用 Python 实现一个简单的基于物品的协同过滤推荐器。MovieLens 1M 包含约 100 万条用户对约 3900 部电影的评分数据。
数据集下载: 你可以从 GroupLens 官网 下载 ml-1m.zip
。解压后主要用到 ratings.dat
文件。
数据格式: UserID::MovieID::Rating::Timestamp
import pandas as pd
import numpy as np
from collections import defaultdict
from itertools import combinations
import math
# --- 1. 加载和预处理数据 ---
# 注意:ml-1m 的数据是用 :: 分隔的,没有表头
ratings_df = pd.read_csv(
'ml-1m/ratings.dat',
sep='::',
engine='python', # 使用 python 引擎处理 :: 分隔符
header=None,
names=['UserID', 'MovieID', 'Rating', 'Timestamp']
)
print("数据加载完成,前5行:")
print(ratings_df.head())
print(f"\n数据总量: {len(ratings_df)}")
print(f"独立用户数: {ratings_df['UserID'].nunique()}")
print(f"独立电影数: {ratings_df['MovieID'].nunique()}")
# 为了简化计算,我们可以先筛选一部分活跃用户和热门电影
# (实际项目中根据需要进行,这里为了演示先跳过,直接使用全量数据计算 ItemCF)
# --- 2. 构建用户-电影评分字典 {UserID: {MovieID: Rating}} ---
user_item_dict = defaultdict(dict)
for index, row in ratings_df.iterrows():
user_item_dict[row['UserID']][row['MovieID']] = row['Rating']
print("\n构建 User-Item 字典完成 (示例):")
# 打印第一个用户看过的电影及评分
user_1_ratings = list(user_item_dict[1].items())[:5]
print(f"用户 1 的部分评分: {user_1_ratings}")
# --- 3. 计算电影相似度 (Item-Based Adjusted Cosine Similarity) ---
# 这一步是 ItemCF 的核心,也是计算量最大的部分
# 3.1 构建电影-用户倒排表 {MovieID: {UserID: Rating}}
item_user_dict = defaultdict(dict)
for user, movies in user_item_dict.items():
for movie, rating in movies.items():
item_user_dict[movie][user] = rating
# 3.2 计算用户平均评分 (用于调整余弦相似度)
user_avg_rating = {}
for user, movies in user_item_dict.items():
user_avg_rating[user] = sum(movies.values()) / len(movies)
# 3.3 计算电影两两之间的相似度
item_similarity = defaultdict(dict)
# 获取所有电影 ID
movie_ids = list(item_user_dict.keys())
print(f"\n开始计算 {len(movie_ids)} 部电影之间的相似度...")
processed_pairs = 0
total_pairs = len(movie_ids) * (len(movie_ids) - 1) / 2
# 遍历所有电影对 (i, j)
for i, j in combinations(movie_ids, 2):
users_i = set(item_user_dict[i].keys())
users_j = set(item_user_dict[j].keys())
common_users = users_i.intersection(users_j)
if len(common_users) > 0: # 至少有一个共同用户才计算相似度
numerator = 0.0
denominator_i = 0.0
denominator_j = 0.0
for user in common_users:
rating_i = item_user_dict[i][user]
rating_j = item_user_dict[j][user]
avg_rating = user_avg_rating[user]
numerator += (rating_i - avg_rating) * (rating_j - avg_rating)
denominator_i += (rating_i - avg_rating) ** 2
denominator_j += (rating_j - avg_rating) ** 2
# 避免分母为零
if denominator_i > 0 and denominator_j > 0:
sim = numerator / (math.sqrt(denominator_i) * math.sqrt(denominator_j))
item_similarity[i][j] = sim
item_similarity[j][i] = sim # 相似度是对称的
processed_pairs += 1
if processed_pairs % 100000 == 0: # 每处理10万对打印一次进度
print(f"已处理 {processed_pairs} / {total_pairs:.0f} 对电影...")
print("\n电影相似度计算完成!")
# 示例:查看电影 1 (Toy Story) 的部分相似电影
movie_1_sim = sorted(item_similarity.get(1, {}).items(), key=lambda x: x[1], reverse=True)[:10]
print(f"与电影 1 (Toy Story) 最相似的部分电影: {movie_1_sim}")
# --- 4. 为特定用户生成推荐 ---
def get_itemcf_recommendations(user_id, user_item_dict, item_similarity, k_similar=20, n_recommend=10):
"""
基于物品协同过滤为用户生成推荐
:param user_id: 目标用户ID
:param user_item_dict: 用户-物品评分字典
:param item_similarity: 物品相似度字典
:param k_similar: 每个物品考虑的最相似物品数量
:param n_recommend: 推荐列表长度
:return: 推荐电影ID列表 [(MovieID, PredictedRating)]
"""
if user_id not in user_item_dict:
print(f"用户 {user_id} 不存在!")
return []
user_watched_movies = user_item_dict[user_id]
recommendations = defaultdict(float)
similarity_sum = defaultdict(float) # 用于加权平均
# 遍历用户看过的每一部电影 i
for movie_i, rating_i in user_watched_movies.items():
# 找到与电影 i 最相似的 K 部电影 j (且用户没看过 j)
similar_movies = sorted(item_similarity.get(movie_i, {}).items(), key=lambda x: x[1], reverse=True)[:k_similar]
for movie_j, sim_ij in similar_movies:
if movie_j not in user_watched_movies: # 只推荐用户没看过的
# 累加预测评分贡献 P_uj = sum(sim_ij * R_ui)
recommendations[movie_j] += sim_ij * rating_i
# 累加相似度总和 sum(|sim_ij|)
similarity_sum[movie_j] += abs(sim_ij)
# 计算最终预测评分 (加权平均)
final_recommendations = []
for movie_j, score_sum in recommendations.items():
if similarity_sum[movie_j] > 0: # 避免除以零
predicted_rating = score_sum / similarity_sum[movie_j]
final_recommendations.append((movie_j, predicted_rating))
# 按预测评分降序排序,取前 N 个
final_recommendations.sort(key=lambda x: x[1], reverse=True)
return final_recommendations[:n_recommend]
# 为用户 1 生成推荐
target_user = 1
recommend_list = get_itemcf_recommendations(target_user, user_item_dict, item_similarity)
print(f"\n为用户 {target_user} 生成的推荐列表 (Top 10):")
print(recommend_list)
# 可以加载 movies.dat 来查看推荐的电影名称
# movies_df = pd.read_csv('ml-1m/movies.dat', sep='::', engine='python', header=None, names=['MovieID', 'Title', 'Genres'], encoding='latin-1')
# movie_id_to_title = pd.Series(movies_df.Title.values, index=movies_df.MovieID).to_dict()
# recommended_titles = [(movie_id_to_title.get(mid, "未知电影"), score) for mid, score in recommend_list]
# print("\n推荐的电影名称:")
# print(recommended_titles)
代码说明:
- 加载数据: 使用 Pandas 加载
ratings.dat
。 - 构建用户-电影字典: 方便按用户查找其评分历史。
- 计算电影相似度:
- 构建电影-用户倒排表,方便查找评价过某电影的所有用户。
- 计算每个用户的平均评分。
- 使用
itertools.combinations
高效遍历所有电影对。 - 对每对电影,找到共同评分用户,应用调整余弦相似度公式计算相似度。这是一个计算密集型步骤。
- 生成推荐:
get_itemcf_recommendations
函数实现了 ItemCF 的推荐逻辑。- 遍历用户看过的电影
i
。 - 找到与
i
最相似的k_similar
部电影j
。 - 如果用户没看过
j
,则累加j
的预测评分贡献 (sim(i,j) * R_ui
) 和相似度总和。 - 最后进行加权平均,得到对未看电影的预测评分,并排序返回 Top-N 推荐。
注意: 上述代码是一个基础实现,用于教学目的。在生产环境中,需要考虑:
- 性能优化: 相似度计算非常耗时,需要使用更高效的数据结构、并行计算(如 Spark)或近似计算方法。
- 库的使用: 可以使用
scikit-surprise
等成熟的推荐系统库,它们封装了多种算法和评估工具。 - 模型更新: 实际系统需要定期更新相似度矩阵和推荐结果。
七、知名应用推荐策略猜想
现实世界中的推荐系统通常非常复杂,会融合多种算法和策略。我们来猜想一下抖音和淘宝可能使用的推荐策略:
7.1 抖音(短视频)
- 核心: 极强的实时性和用户沉浸感。
- 可能策略:
- Item-Based CF / Graph-Based: 用户刷视频的行为序列非常密集,非常适合计算视频之间的相似性(例如,看完 A 又马上看完 B 的用户很多,则 A 和 B 可能相似)。基于图的模型(如 Swing)可能效果很好。
- 深度学习模型 (Deep Learning): 利用丰富的特征(视频内容特征、音频特征、用户属性、交互行为序列、社交关系等)构建复杂的深度模型(如 DeepFM, Wide & Deep, DIN)来预测用户的点击率、观看时长、完播率、点赞、评论、分享等多种目标。
- 实时反馈: 用户对视频的快速反馈(划走、停留时长、点赞等)被迅速捕捉并用于调整后续推荐。
- 探索与利用 (Explore & Exploit): 在推荐已知偏好的内容(利用)的同时,也需要推荐一些新内容或用户可能潜在感兴趣的内容(探索),以避免信息茧房。
- 场景化推荐: 区分不同场景(如首页推荐、关注页、搜索后推荐)采用不同策略。
7.2 淘宝(电商)
- 核心: 促进用户购买转化,提升 GMV(商品交易总额)。
- 可能策略:
- 混合推荐: 广泛使用混合策略。
- 协同过滤 (UserCF & ItemCF): “购买过 A 的人也购买了 B” (ItemCF),“与你相似的人购买了 C” (UserCF)。
- 基于内容: 根据用户浏览/购买的商品属性(类别、品牌、标签)推荐相似商品。
- 用户画像: 结合用户的人口统计学信息、购买力、活跃度、历史搜索/浏览/购买/收藏/加购行为构建精细的用户画像。
- 行为序列建模: 利用用户的实时行为序列(如 RNN, LSTM, Transformer)预测用户的下一个行为(点击?购买?)。阿里巴巴的 DIN (Deep Interest Network) 模型就是这方面的代表,能捕捉用户多样化的兴趣。
- 多目标优化: 不仅要预测点击率(CTR),还要预测转化率(CVR)、客单价等多个商业目标。
- 召回与排序 (Recall & Ranking): 通常分为两阶段:
- 召回: 从海量商品库中快速筛选出几百或几千个候选商品(可能用到多种召回策略,如 ItemCF、热门、内容相似等)。
- 排序: 使用复杂的机器学习模型(如 GBDT+LR, DeepFM, Wide & Deep)对候选商品进行精准排序,综合考虑用户偏好、商品质量、商业目标等因素。
- 冷启动处理: 对新用户和新商品有专门的策略(如引导、内容推荐、流量扶持)。
- 混合推荐: 广泛使用混合策略。
八、总结
本文深入探讨了个性化推荐系统的核心算法与相关技术,旨在帮助读者建立对推荐系统的系统性认识。以下是本文的核心内容总结:
- 推荐系统类型: 主要包括协同过滤(基于用户行为相似性)、基于内容推荐(基于物品属性和用户画像相似性)以及结合两者优点的混合推荐。
- 协同过滤详解:
- User-Based CF: 找到相似用户,推荐他们喜欢的物品。适用于用户兴趣变化快场景。
- Item-Based CF: 找到用户喜欢的物品的相似物品进行推荐。适用于兴趣相对稳定、物品少于用户场景,易于实现和解释。
- 矩阵分解 (SVD/Latent Factor Model): 通过学习用户和物品的低维隐向量来预测评分,能处理数据稀疏性,泛化能力强,精度通常更高。
- 基于内容推荐: 通过提取物品特征和构建用户画像,计算内容相似度进行推荐,对新物品友好,可解释性强,但难以发现新兴趣。
- 推荐系统评估: 介绍了常用的离线评估指标,包括 Precision@K、Recall@K(关注准确率和召回率)、MAP、NDCG@K(关注排序质量和相关性等级)以及覆盖率、多样性等。
- 冷启动问题: 分析了用户冷启动、物品冷启动和系统冷启动的挑战,并介绍了相应的解决方案(如利用初始信息、内容推荐、引导交互等)。
- Python 实战: 提供了一个基于 MovieLens 数据集实现 ItemCF 的基础 Python 代码示例,展示了从数据加载、相似度计算到生成推荐的完整流程。
- 应用策略猜想: 探讨了抖音和淘宝等大型应用可能采用的复杂推荐策略,强调了混合方法、深度学习、实时反馈、多目标优化等在实际应用中的重要性。
推荐系统是一个充满活力且不断发展的领域,涉及机器学习、数据挖掘、信息检索等多个学科。希望本文能为你打开探索用户兴趣奥秘的大门,并为后续深入学习和实践打下坚实的基础。