本项目基于MovieLens电影评分数据集,实现并系统性地比较了八种主流推荐算法的性能表现。实现的算法涵盖了基于内容的推荐(标签推荐、LDA主题模型)、协同过滤(基于用户和物品的KNN)、矩阵分解(SVD)、以及新兴的深度学习方法(基于图的推荐、张量分解),构建了一个完整的推荐系统评估框架。
本研究的主要贡献包括: 算法实现:提供了8种推荐算法的标准化实现,包括:
- 基于标签的推荐(Tag-based)
- 基于张量分解的推荐(Tensor-based)
- 基于LDA主题模型的推荐(LDA-based)
- 基于图的推荐(Graph-based)
- 基于用户最近邻的推荐(User-KNN)
- 基于物品最近邻的推荐(Item-KNN)
- 基于SVD的推荐(SVD-based)
- 基于Slope One的推荐(Slope One)
recommend/
├── README.md # 项目说明文档
├── requirements.txt # 项目依赖
├── main.py # 主程序(算法比较)
├── venv/ # Python虚拟环境
│ ├── Lib/ # 虚拟环境库文件
│ ├── Scripts/ # 可执行文件
│ └── pyvenv.cfg # 虚拟环境配置
├── models/ # 推荐算法模型
│ ├── base_recommender.py # 基类
│ ├── tag_based_recommender.py # 基于标签
│ ├── tensor_recommender.py # 基于张量分解
│ ├── lda_recommender.py # 基于LDA主题
│ ├── graph_recommender.py # 基于图
│ ├── user_knn_recommender.py # 基于用户KNN
│ ├── item_knn_recommender.py # 基于物品KNN
│ ├── svd_recommender.py # 基于SVD
│ └── slope_one_recommender.py # 基于Slope One
├── examples/ # 示例代码
│ ├── tag_based_example.py
│ ├── tensor_based_example.py
│ ├── lda_based_example.py
│ ├── graph_based_example.py
│ ├── user_knn_example.py
│ ├── item_knn_example.py
│ ├── svd_example.py
│ └── slope_one_example.py
└── utils/ # 工具类
├── data_loader.py # 数据加载
└── metrics.py # 评估指标
符号 | 含义 | 使用场景 |
---|---|---|
U, I | 用户-标签矩阵,物品-标签矩阵 | Tag-based, SVD |
uᵢⱼ, iᵢⱼ | 矩阵中的元素值 | Tag-based, SVD |
sim(a,b) | a与b之间的相似度 | 所有基于相似度的算法 |
cosine(x,y) | x与y的余弦相似度 | 相似度计算 |
X | 三阶张量 | Tensor-based |
ℝᵐˣⁿˣᵏ | m×n×k维实数空间 | Tensor-based |
Σᵣ | 对下标r求和 | Tensor-based, SVD |
θ, φ | 主题分布,标签分布 | LDA-based |
α, β | Dirichlet分布参数 | LDA-based |
G(V,E) | 图的顶点集和边集 | Graph-based |
eᵤ, eᵢ | 节点的嵌入向量 | Graph-based |
σ(x) | Sigmoid激活函数 | Graph-based |
Rᵤ, Rᵥ | 用户的评分向量 | User-KNN |
Rᵢ, Rⱼ | 物品的评分向量 | Item-KNN |
Nₖ(x) | x的k个最近邻集合 | KNN-based |
r̂ᵤᵢ | 预测的评分值 | 所有算法 |
dev(i,j) | 物品i和j之间的评分偏差 | Slope One |
S(i,j) | 同时评价过物品i和j的用户集 | Slope One |
R(u) | 用户u评价过的物品集 | 多个算法 |
μ | 全局平均评分 | SVD |
bᵤ, bᵢ | 用户和物品的偏置项 | SVD |
-
基于标签的推荐 (Tag-based)
- 利用用户和物品的标签信息
- 适合处理冷启动问题
- 可以提供解释性推荐
- 定义:利用用户和物品的标签信息构建用户和物品的特征表示,通过标签相似度进行推荐
- 数学原理:
- 用户-标签矩阵:U = [uᵢⱼ],uᵢⱼ表示用户i对标签j的使用频率
- 物品-标签矩阵:I = [iᵢⱼ],iᵢⱼ表示物品i被标签j标注的频率
- 相似度计算:sim(u,i) = cosine(Uᵤ, Iᵢ),其中Uᵤ是用户的标签向量,Iᵢ是物品的标签向量
- 优点:
- 解决冷启动问题
- 提供可解释性推荐
- 能够捕捉用户兴趣和物品特征
- 局限性:
- 依赖标签质量
- 无法处理标签稀疏问题
- 计算复杂度较高
-
基于张量分解的推荐 (Tensor-based)
- 将用户-物品-标签关系建模为三维张量
- 使用CP分解捕获多维特征
- 可以同时建模多种关系
- 定义:将用户-物品-标签的三维关系建模为张量,通过张量分解学习潜在特征
- 数学原理:
- 构建三阶张量:X ∈ ℝᵐˣⁿˣᵏ,其中m、n、k分别是用户、物品、标签数量
- CP分解:X ≈ Σᵣ aᵣ ∘ bᵣ ∘ cᵣ
- aᵣ ∈ ℝᵐ:用户潜在特征向量
- bᵣ ∈ ℝⁿ:物品潜在特征向量
- cᵣ ∈ ℝᵏ:标签潜在特征向量
- 预测得分:score(u,i) = Σᵣ aᵤᵣ × bᵢᵣ
- 优点:
- 可以同时建模多种关系
- 捕获高阶相关性
- 具有较强的表达能力
- 局限性:
- 计算复杂度高
- 需要较大内存
- 参数调优困难
-
基于LDA主题模型的推荐 (LDA-based)
- 使用LDA发现物品的隐含主题
- 建模用户的主题偏好
- 提供可解释的主题特征
- 定义:使用LDA(Latent Dirichlet Allocation)发现物品的隐含主题,并基于主题相似度进行推荐
- 数学原理:
- 生成过程:
- θ ~ Dirichlet(α):用户的主题分布
- φ ~ Dirichlet(β):主题的标签分布
- z ~ Multinomial(θ):为每个标签选择主题
- w ~ Multinomial(φ_z):生成标签
- 主题提取:使用Gibbs采样估计参数
- 相似度计算:sim(u,i) = cosine(θᵤ, θᵢ)
- 生成过程:
- 优点:
- 提供语义层面的推荐
- 可解释性强
- 能够发现潜在主题
- 局限性:
- 需要大量文本数据
- 主题数量需要预设
- 训练时间较长
-
基于图的推荐 (Graph-based)
- 构建用户-物品-标签异构图
- 使用node2vec学习节点表示
- 捕获复杂的网络结构特征
- 定义:构建用户-物品-标签的异构图网络,通过图嵌入学习节点表示
- 数学原理:
- 图构建:G = (V, E)
- V = Vᵤ ∪ Vᵢ ∪ Vₜ:用户、物品、标签节点集
- E:节点间的边集
- Node2Vec随机游走:
- 返回参数p:控制返回前一节点的概率
- 外出参数q:控制探索远处节点的倾向
- 节点嵌入:通过Skip-gram模型学习节点表示
- 预测得分:score(u,i) = σ(eᵤᵀeᵢ),其中eᵤ、eᵢ为节点嵌入向量
- 图构建:G = (V, E)
- 优点:
- 捕获复杂的网络结构
- 考虑高阶连接关系
- 可以整合多种信息
- 局限性:
- 图构建方式影响性能
- 计算资源消耗大
- 参数敏感
-
基于用户最近邻的推荐 (User-KNN)
- 基于用户相似度进行协同过滤
- 计算简单,易于实现
- 推荐结果具有很好的解释性
- 定义:基于用户间的相似度进行协同过滤,利用相似用户评分预测目标用户的偏好
- 数学原理:
- 用户相似度:sim(u,v) = cosine(Rᵤ, Rᵥ)
- Rᵤ、Rᵥ为用户的评分向量
- 预测评分:r̂ᵤᵢ = Σᵥ∈Nₖ(u) sim(u,v)×rᵥᵢ / Σᵥ∈Nₖ(u) sim(u,v)
- Nₖ(u)为用户u的k个最近邻
- 用户相似度:sim(u,v) = cosine(Rᵤ, Rᵥ)
- 优点:
- 实现简单直观
- 推荐结果可解释
- 能够快速适应用户兴趣变化
- 局限性:
- 稀疏数据表现差
- 计算复杂度高
- 冷启动问题明显
-
基于物品最近邻的推荐 (Item-KNN)
- 基于物品相似度进行协同过滤
- 相比User-KNN更稳定
- 适合物品数少于用户数量的场景
- 定义:基于物品间的相似度进行协同过滤,利用用户对相似物品的评分预测目标物品的评分
- 数学原理:
- 物品相似度:sim(i,j) = cosine(Rᵢ, Rⱼ)
- Rᵢ、Rⱼ为物品的评分向量
- 预测评分:r̂ᵤᵢ = Σⱼ∈Nₖ(i) sim(i,j)×rᵤⱼ / Σⱼ∈Nₖ(i) sim(i,j)
- Nₖ(i)为物品i的k个最近邻
- 物品相似度:sim(i,j) = cosine(Rᵢ, Rⱼ)
- 优点:
- 相比User-KNN更稳定
- 预计算物品相似度
- 适合物品数少于用户数的场景
- 局限性:
- 无法利用物品内容特征
- 新物品冷启动问题
- 相似度计算开销大
-
基于SVD的推荐 (SVD-based)
- 使用奇异值分解进行矩阵分解
- 可以有效处理稀疏数据
- 计算效率高,扩展性好
- 定义:通过奇异值分解进行矩阵分解,学习用户和物品的潜在特征表示
- 数学原理:
- 评分矩阵分解:R ≈ UΣVᵀ
- U ∈ ℝᵐˣᵏ:用户潜在特征矩阵
- Σ ∈ ℝᵏˣᵏ:奇异值对角矩阵
- V ∈ ℝⁿˣᵏ:物品潜在特征矩阵
- 预测评分:r̂ᵤᵢ = μ + bᵤ + bᵢ + uᵤᵀvᵢ
- μ:全局平均评分
- bᵤ、bᵢ:用户和物品偏置项
- 评分矩阵分解:R ≈ UΣVᵀ
- 优点:
- 可以处理稀疏数据
- 降维效果好
- 计算效率高
- 局限性:
- 可解释性较差
- 容易过拟合
- 需要调优多个参数
-
基于Slope One的推荐 (Slope One)
- 使用加权Slope One算法
- 考虑评分偏差
- 简单高效,适合在线推荐
- 定义:一种基于评分差值的协同过滤算法,考虑物品间的评分偏差进行预测
- 数学原理:
- 物品间偏差:dev(i,j) = Σᵤ∈S(i,j) (rᵤᵢ - rᵤⱼ) / |S(i,j)|
- S(i,j)为同时评价过物品i和j的用户集
- 预测评分:r̂ᵤᵢ = Σⱼ∈R(u) (rᵤⱼ + dev(i,j)) / |R(u)|
- R(u)为用户u评价过的物品集
- 物品间偏差:dev(i,j) = Σᵤ∈S(i,j) (rᵤᵢ - rᵤⱼ) / |S(i,j)|
- 优点:
- 算法简单高效
- 考虑评分偏差
- 适合在线推荐
- 局限性:
- 需要足够的共同评分
- 偏差计算可能不稳定
- 没有考虑用户相似度
本项目采用了四个主要的评估指标来衡量推荐算法的性能。所有指标都基于 Top-K 推荐列表进行计算,其中 K=10。
- 定义:在推荐的 K 个物品中,有多少比例是用户实际感兴趣的
- 计算方法:正确推荐的物品数量 / K
- 取值范围:[0, 1],越高越好
- 特点:
- 反映推荐的准确性
- 不考虑排序位置
- 适合评估推荐的精确度
- 定义:在用户实际感兴趣的所有物品中,推荐系统找到了多少比例
- 计算方法:正确推荐的物品数量 / 用户实际感兴趣的总物品数
- 取值范围:[0, 1],越高越好
- 特点:
- 反映推荐的覆盖程度
- 不考虑排序位置
- 适合评估推荐的完整性
- 定义:考虑排序位置的推荐质量度量,越靠前的正确推荐贡献越大
- 计算方法:实际DCG值 / 理想DCG值
- DCG = rel₁ + Σᵢ₌₂ᵏ (relᵢ / log₂(i+1))
- rel为相关性分数(本项目中使用二元值:0或1)
- 取值范围:[0, 1],越高越好
- 特点:
- 考虑推荐的排序质量
- 对靠前位置的错误更敏感
- 适合评估排序效果
- 定义:对每个相关物品的位置进行平均,得到一个综合的排序质量度量
- 计算方法:
- 对每个相关物品的位置计算精度
- 对所有精度值取平均
- 取值范围:[0, 1],越高越好
- 特点:
- 综合考虑准确率和排序质量
- 对完整的推荐列表进行评估
- 适合整体性能评估
- 业务场景:
- 强调准确性:关注 Precision@K
- 强调覆盖性:关注 Recall@K
- 强调排序质量:关注 NDCG@K
- 综合评估:关注 MAP@K
- 算法比较:
- 建议同时观察多个指标
- NDCG@K 通常是最重要的参考指标
- 不同指标可能会有所矛盾,需要根据实际需求权衡
在本项目的实验中,各算法在不同指标上表现各异:
- 基于内容的算法(Tag-based, LDA-based)通常在 Precision@K 上表现较好
- 协同过滤算法(User-KNN, Item-KNN)在 Recall@K 上有优势
- 混合方法(Graph-based, Tensor-based)在 NDCG@K 上较为平衡
- 矩阵分解方法(SVD-based)在 MAP@K 上表现稳定
- 环境配置
首先创建并激活Python虚拟环境:(建议使用本项目中提供的虚拟环境venv)
# 创建虚拟环境
python -m venv venv
# 在Windows上激活虚拟环境
.\venv\Scripts\activate
# 在Linux/Mac上激活虚拟环境
source venv/bin/activate
然后在虚拟环境中安装依赖:
pip install -r requirements.txt
- 数据准备
- 下载MovieLens数据集(ml-latest-small)
- 将数据集放在项目根目录下
- 运行示例
# 运行单个算法示例
python examples/tag_based_example.py
python examples/tensor_based_example.py
# ... 其他算法示例
# 运行算法比较
python main.py
- 查看结果
algorithm_comparison.png
: 性能对比图algorithm_comparison.csv
: 详细评估结果
主要实验结果包括:
- 各算法在不同指标上的表现
- 算法运行时间对比
- 推荐结果的多样性分析
- 冷启动情况下的性能比较
项目设计考虑了良好的扩展性:
-
新算法扩展
- 继承BaseRecommender类
- 实现必要的接口方法
- 添加到main.py的评估流程
-
新指标扩展
- 在metrics.py中添加新指标
- 在评估流程中使用新指标
-
数据集扩展
- 修改data_loader.py支持新数据集
- 保持与现有接口兼容
-
虚拟环境
- 建议使用虚拟环境运行项目,避免依赖冲突
- 运行代码前确保已激活虚拟环境(命令行前缀显示
(venv)
) - 如遇依赖问题,可以删除
venv
目录重新创建
-
内存使用
- 部分算法(如Tensor-based)可能需要较大内存
- 建议使用小数据集进行测试
-
运行时间
- 图算法和张量算法计算较慢
- 可以调整参数在效果和速度间平衡
-
参数调整
- 不同算法有其特定的关键参数
- 建议根据具体场景调整参数
欢迎贡献代码,请遵循以下步骤
- Fork本项目
- 创建特性分支
- 提交更改
- 发起Pull Request
MIT License
- MovieLens数据集: F. Maxwell Harper and Joseph A. Konstan. 2015. The MovieLens Datasets: History and Context. ACM Transactions on Interactive Intelligent Systems (TiiS) 5, 4: 19:1–19:19.
- 各算法相关论文(详见各算法类的文档字符串)