【机器学习】万字长文:深入剖析推荐系统核心算法 (协同过滤/内容/SVD) 与Python实战

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 尚未接触过的物品。

工作流程:

  1. 找到相似用户: 计算目标用户 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)=iIUV(RUiRˉU)2 iIUV(RViRˉV)2 iIUV(RUiRˉU)(RViRˉ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 =iIURUi2 iIVRVi2 iIUVRUiRVi
      这里 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 交互过的物品集合。
  2. 生成推荐: 找到与用户 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+VNeighbors(U)Sim(U,V)VNeighbors(U)Sim(U,V)×(RVjRˉ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=VNeighbors(U)Sim(U,V)VNeighbors(U)Sim(U,V)×RVj
    最后将预测评分最高的若干物品推荐给用户 U。

优点: 能够推荐不同领域的新物品,发现用户的潜在兴趣。
缺点: 用户数量通常远大于物品数量,计算用户相似度矩阵开销大;用户相似度会随着新用户加入或用户兴趣变化而改变,需要频繁更新;在用户行为稀疏时效果不佳。

2.1.2 基于物品的协同过滤 (Item-Based Collaborative Filtering, ItemCF)

核心思想: 给用户 U 推荐那些与他过去喜欢的物品相似的物品。

工作流程:

  1. 计算物品相似度: 计算物品 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)=UUij(RUiRˉU)2 UUij(RUjRˉU)2 UUij(RUiRˉU)(RUjRˉ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(I i,I j)=∣∣I i∣∣∣∣I j∣∣I iI j=UUiRUi2 UUjRUj2 UUijRUiRUj
      其中 U i U_i Ui U j U_j Uj 分别是对物品 i 和 j 评过分的用户集合。
  2. 生成推荐: 找到用户 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=iN(U)Neighbors(j)Sim(i,j)iN(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 p U 和物品向量 q ⃗ i \vec{q}_i q i 的点积来近似估计:
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^Uip UTq i=k=1KpUkqik
其中 K 是隐语义空间的维度(一个超参数,远小于用户数和物品数)。 p ⃗ U \vec{p}_U p U 表示用户的偏好在各个隐因子上的强度, q ⃗ i \vec{q}_i q i 表示物品在各个隐因子上的分布。这些隐因子可能是无法直观解释的,例如代表电影的“喜剧程度”、“动作程度”或者用户的“偏爱文艺片程度”等。

模型学习: 目标是找到最优的用户向量 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(RUip UTq i)2+λ(∣∣p U2+∣∣q i2)
其中 Observed 表示所有已知的用户-物品评分记录。正则化项 λ ( ∣ ∣ p ⃗ U ∣ ∣ 2 + ∣ ∣ q ⃗ i ∣ ∣ 2 ) \lambda (||\vec{p}_U||^2 + ||\vec{q}_i||^2) λ(∣∣p U2+∣∣q i2) 用于防止过拟合, λ \lambda λ 是正则化系数。

常用的优化算法包括:

  • 随机梯度下降 (Stochastic Gradient Descent, SGD): 对每个已知的评分样本 ( U , i ) (U, i) (U,i),按照梯度的反方向更新 p ⃗ U \vec{p}_U p U q ⃗ i \vec{q}_i q i
    • 计算误差: e U i = R U i − p ⃗ U T q ⃗ i e_{Ui} = R_{Ui} - \vec{p}_U^T \vec{q}_i eUi=RUip UTq i
    • 更新规则:
      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) p Up U+γ(eUiq iλp U)
      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) q iq i+γ(eUip Uλq i)
      其中 γ \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+p UTq i
其中 μ \mu μ 是全局平均评分, b U b_U bU 是用户 U 的评分偏置(有的用户倾向于打高分), b i b_i bi 是物品 i 的评分偏置(有的物品普遍评分较高)。

优点: 能够处理数据稀疏性问题;模型泛化能力强;可以学习到潜在的关联;预测精度通常优于基于记忆的方法。
缺点: 模型训练过程计算量较大;学习到的隐因子缺乏直观解释性。

三、基于内容的推荐:懂你所爱

基于内容的推荐不依赖其他用户的行为,而是专注于用户自身的历史偏好和物品的内容特征。

3.1 原理与流程

核心思想: 基于用户过去喜欢(例如,评分高、点击、购买)的物品的内容特征,构建用户的偏好画像(User Profile),然后推荐与该画像匹配的物品。

工作流程:

  1. 物品特征提取 (Item Representation): 对物品进行内容分析,提取关键特征。

    • 电影: 类型、导演、演员、关键词、剧情简介等。
    • 新闻文章: 关键词、主题分类(TF-IDF、LDA)、实体、来源等。
    • 商品: 品牌、类别、标签、描述文本、价格等。
      将这些特征表示成向量形式(例如,使用 TF-IDF 向量表示文本特征)。
  2. 用户偏好建模 (User Profile Learning): 根据用户历史交互过的物品的特征,构建用户的偏好画像向量。

    • 简单方法:将用户喜欢过的所有物品的特征向量进行加权平均(例如,用评分作为权重)。
    • 复杂方法:训练一个分类器(如逻辑回归、SVM),预测用户是否会喜欢某个特定特征的物品。
  3. 匹配与推荐 (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(Profile User,Feature Item)

优点:

  • 用户独立性: 用户之间的推荐互不影响。
  • 可解释性: 可以向用户解释推荐原因(例如,“因为你喜欢科幻电影,所以为你推荐这部”)。
  • 新物品友好: 只要物品有内容描述,就能立即进行推荐,没有冷启动问题。
  • 无需大量用户数据: 即使只有一个用户的行为数据也可以进行推荐。

缺点:

  • 特征工程依赖: 推荐效果严重依赖于物品特征提取的质量。
  • 过度专业化/惊喜度低: 推荐结果往往与用户历史兴趣高度相似,难以发现新的兴趣领域。
  • 新用户冷启动: 对于没有任何历史行为的新用户,无法建立准确的用户画像(需要一些初始信息或默认推荐)。

四、评估推荐系统:好不好,量化说了算

如何衡量一个推荐系统的好坏?我们需要一套客观的评估指标。评估通常分为离线评估、在线评估(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@KRecommendedItems@KRelevantItems=推荐列表长度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=RelevantItemsRecommendedItems@KRelevantItems=用户实际喜欢的总数预测对的数量
    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=1K(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=Users1uUsersAPu

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=1Kreli
    其中 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=1Klog2(i+1)reli或者DCG@K=rel1+i=2Klog2(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)

代码说明:

  1. 加载数据: 使用 Pandas 加载 ratings.dat
  2. 构建用户-电影字典: 方便按用户查找其评分历史。
  3. 计算电影相似度:
    • 构建电影-用户倒排表,方便查找评价过某电影的所有用户。
    • 计算每个用户的平均评分。
    • 使用 itertools.combinations 高效遍历所有电影对。
    • 对每对电影,找到共同评分用户,应用调整余弦相似度公式计算相似度。这是一个计算密集型步骤。
  4. 生成推荐:
    • 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): 通常分为两阶段:
      1. 召回: 从海量商品库中快速筛选出几百或几千个候选商品(可能用到多种召回策略,如 ItemCF、热门、内容相似等)。
      2. 排序: 使用复杂的机器学习模型(如 GBDT+LR, DeepFM, Wide & Deep)对候选商品进行精准排序,综合考虑用户偏好、商品质量、商业目标等因素。
    • 冷启动处理: 对新用户和新商品有专门的策略(如引导、内容推荐、流量扶持)。

八、总结

本文深入探讨了个性化推荐系统的核心算法与相关技术,旨在帮助读者建立对推荐系统的系统性认识。以下是本文的核心内容总结:

  1. 推荐系统类型: 主要包括协同过滤(基于用户行为相似性)、基于内容推荐(基于物品属性和用户画像相似性)以及结合两者优点的混合推荐。
  2. 协同过滤详解:
    • User-Based CF: 找到相似用户,推荐他们喜欢的物品。适用于用户兴趣变化快场景。
    • Item-Based CF: 找到用户喜欢的物品的相似物品进行推荐。适用于兴趣相对稳定、物品少于用户场景,易于实现和解释。
    • 矩阵分解 (SVD/Latent Factor Model): 通过学习用户和物品的低维隐向量来预测评分,能处理数据稀疏性,泛化能力强,精度通常更高。
  3. 基于内容推荐: 通过提取物品特征和构建用户画像,计算内容相似度进行推荐,对新物品友好,可解释性强,但难以发现新兴趣。
  4. 推荐系统评估: 介绍了常用的离线评估指标,包括 Precision@K、Recall@K(关注准确率和召回率)、MAP、NDCG@K(关注排序质量和相关性等级)以及覆盖率、多样性等。
  5. 冷启动问题: 分析了用户冷启动、物品冷启动和系统冷启动的挑战,并介绍了相应的解决方案(如利用初始信息、内容推荐、引导交互等)。
  6. Python 实战: 提供了一个基于 MovieLens 数据集实现 ItemCF 的基础 Python 代码示例,展示了从数据加载、相似度计算到生成推荐的完整流程。
  7. 应用策略猜想: 探讨了抖音和淘宝等大型应用可能采用的复杂推荐策略,强调了混合方法、深度学习、实时反馈、多目标优化等在实际应用中的重要性。

推荐系统是一个充满活力且不断发展的领域,涉及机器学习、数据挖掘、信息检索等多个学科。希望本文能为你打开探索用户兴趣奥秘的大门,并为后续深入学习和实践打下坚实的基础。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吴师兄大模型

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值