推荐算法之用矩阵分解做协调过滤——LFM模型
隐语义模型(Latent factor model,以下简称LFM),是推荐系统领域上广泛使用的算法。它将矩阵分解应用于推荐算法推到了新的高度,在推荐算法历史上留下了光辉灿烂的一笔。本文将对 LFM 原理进行详细阐述,给出其基本算法原理。此外,还将介绍使得隐语义模型声名大噪的算法FunkSVD和在其基础上改进较为成功的BiasSVD。最后,对LFM进行一个较为全面的总结。
1. 矩阵分解应用于推荐算法要解决的问题
在推荐系统中,我们经常可能面临的场景是:现有大量用户和物品,以及少部分用户对少部分物品的评分,我们需要使用现有的用户对少部分物品的评分去推测用户对物品集中其他物品的可能的评分,从而将预测中评分高的物品推荐给用户。例如下面的用户物品评分表:
| 用户\物品 | 物品 1 | 物品 2 | 物品 3 | 物品 4 | 物品 5 |
|---|---|---|---|---|---|
| 用户 1 | 3 | 2 | |||
| 用户 2 | 1 | 2 | 6 | ||
| 用户 3 | 3 | 4 | 6 | ||
| 用户 4 | 1 | 2 | 5 | ||
| 用户 5 | 4 | 2 | 3 |
对于每个用户,我们希望较准确的预测出其对未评分物品的评分。将m个用户和n个物品的评分看做一个矩阵M,从而将矩阵分解应用到该场景,即可解决这一问题。而本文,将关注于矩阵分解用于到推荐的方法之一,即LFM算法的解决方案。
2. LFM
LFM算法的核心思想是通过隐含特征(Latent factor)联系用户和物品,该算法最早在文本挖掘领域中被提出用于找到文本的隐含语义,相关名词还有LDA和Topic Model等。
2.1 如何表示用户的偏好和物品(item)属性?
在被问到这个问题时,针对MovieLens(电影评分)数据集,你可能会说用户是否喜欢动作片,物品所属电影类型去回答。但用户对其他类型的电影的偏好程度呢?物品在其它类型所占的权重又是多少呢?就算针对现有的电影类型去表征用户偏好和物品,那么能否能够完全的表示出用户的偏好和物品属性呢?答案是不能,比如用户喜欢看成龙的电影这个偏好没法表示出来,电影由谁导演,主演是谁没法表示。但你要问我用哪些属性去表征呢?这个谁也无法给出一个很好的答案,粒度很难控制。
2.2 LFM 来救场
隐语义模型较好的解决了该问题,它从数据出发,通过基于用户行为统计的自动聚类,可指定出表征用户偏好和物品的向量维度,最终得到用户的偏好向量以及物品的表征向量。LFM通过以下公式计算用户u对物品i的偏好:
\[
preference(u, i)=p^T_u q_i=\sum_f^F{p_{u,k}q_{i,k}}
\]
这个公式,\(p_{u,k}\)度量了用户u的偏好和第f个隐类的关系,\(q_{i,k}\)度量了物品i和第f个隐类的关系。
那么现在,我们期望用户的评分矩阵M这样分解:
\[
M_{m*n}=P^T_{m*k}Q_{k*n}
\]
那么,我们如何将矩阵分解呢?这里采用了线性回归的思想,即尽可能的让用户的评分和我们预测的评分的残差尽可能小,也就是说,可以用均方差作为损失函数来寻找最终的P和Q。考虑所有的用户和样本的组合,我们期望的最小化损失函数为:
\[
\sum_{i,j}{(m_{ij}-p_i^Tq_j)^2}
\]
只要我们能够最小化上面的式子,并求出极值所对应的\(p_i\) 和\(q_j\),则我们最终可以得到矩阵P和Q,那么对于任意矩阵M任意一个空白评分的位置,我们就可以通过\(p^T_i q_j\)计算预测评分。
2.3 FunkSVD用于推荐
上面是隐语义模型LFM的基本原理,但在实际业务中,为防止过拟合,我们常常会加入一个L2的正则化项,这也就诞生了我们的FunkSVD算法。其优化目标函数\(J(p,q)\)定义为:
\[
\underbrace{argmin}_{p_i,q_j}\sum_{i,j}{(m_{ij}-p^T_iq_j)^2+\lambda({\Arrowvert{p_i}\Arrowvert}^2_2+{\Arrowvert{q_i}\Arrowvert}^2_2)}
\]
其中λ为正则化系数,需要调参。对于这个优化问题,我们一般通过梯度下降法来进行优化得到结果。
将上式分别对\(p_i\)和\(q_j\)求导我们得到:
\[
\frac{\partial{J}}{\partial{p_i}}=-2(m_{ij}-p^T_iq_j)q_j+2\lambda{p_i}
\]
\[
\frac{\partial{J}}{\partial{q_j}}=-2(m_{ij}-p^T_iq_j)p_i+2\lambda{q_j}
\]
则梯度下降中迭代公式为:
\[
p_i = p_i +\alpha((m_{ij}-p^T_iq_j)q_j-\lambda{p_i})
\]
\[
q_j = q_j+\alpha((m_{ij}-p^T_iq_j)p_i-\lambda{q_j})
\]
通过迭代我们最终可以得到P和Q,进而用于推荐。
为读者进一步理解,笔者实现了基于MovieLens数据集实现了该方法。代码详见github: FunkSVD算法实现
2.4 BiasSVD用于推荐
BiasSVD是FunkSVD较为成功的改进版算法。BiasSVD假设评分系统包括三部分的偏置因素:一些和用户物品无关的评分因素。用户有一些和物品无关的评分因素,称为用户偏置项。而物品也有一些和用户无关的评分因素,称为物品偏置项。这很好理解,对于乐观的用户来说,它的评分行为普遍偏高,而对批判性用户来说,他的评分记录普遍偏低,即使他们对同一物品的评分相同,但是他们对该物品的喜好程度却并不一样。同理,对物品来说,以电影为例,受大众欢迎的电影得到的评分普遍偏高,而一些烂片的评分普遍偏低,这些因素都是独立于用户或产品的因素,而和用户对产品的的喜好无关。
假设评分系统平均分为μ,第i个用户的用户偏置项为\(b_i\),而第j个物品的物品偏置项为\(b_j\),则加入了偏置项以后的优化目标函数\(J(p_i,q_j)\)是这样的:
\[
\underbrace{argmin}_{p_i,q_j}\sum_{i,j}{(m_{ij}-p^T_iq_j-u-b_i-b_j)^2+\lambda({\Arrowvert{p_i}\Arrowvert}^2_2+{\Arrowvert{q_i}\Arrowvert}^2_2+{\Arrowvert{b_i}\Arrowvert}^2_2+{\Arrowvert{b_j}\Arrowvert}^2_2)}
\]
这个优化目标也可以采用梯度下降法求解。和·FunkSVD不同的是,此时我们多了两个偏执项\(b_i\)和 \(b_j\),\(p_i\)和\(q_j\)的迭代公式和FunkSVD类似,只是每一步的梯度导数稍有不同而已。\(b_i\)和 \(b_j\)一般可以初始设置为0,然后参与迭代。迭代公式为:
\[
p_i = p_i +\alpha((m_{ij}-p^T_iq_j-u-b_i-b_j)q_j-\lambda{p_i})
\]
\[
q_j = q_j+\alpha((m_{ij}-p^T_iq_j-u-b_i-b_j)p_i-\lambda{q_j})
\]
\[
b_i=b_i+\alpha(m_{ij}-p^T_iq_j-u-b_i-b_j-\lambda{b_i})
\]
\[
b_j=b_j+\alpha(m_{ij}-p^T_iq_j-u-b_i-b_j-\lambda{b_j})
\]
通过迭代我们最终可以得到P和Q,进而用于推荐。BiasSVD增加了一些额外因素的考虑,因此在某些场景会比FunkSVD表现好。
为读者进一步理解,笔者实现了基于MovieLens数据集实现了该方法。代码详见github:BiasSVD算法实现
小结
LFM 是一种基于机器学习的方法,具有比较好的理论基础,通过优化一个设定的指标建立最优的模型。它实质上是矩阵分解应用到推荐的方法,其中FunkSVD更是将矩阵分解用于推荐方法推到了新的高度,在实际应用中使用非常广泛。当然矩阵分解方法也在不停的进步,目前矩阵分解推荐算法中分解机方法(matrix factorization, MF)使用最为广泛。
对于矩阵分解用于推荐方法本身来说,它容易编程实现,实现复杂度低,预测效果也好,同时还能保持扩展性。这些都是其宝贵的优点。但是LFM无法给出很好的推荐解释,它计算出的隐类虽然在语义上确实代表了一类兴趣和物品,却很难用自然语言描述并生成解释展现给用户。
LFM 在建模过程中,假设有 M 个用户、 N 个物品、 K 条用户对物品的行为记录,如果是 F 个隐类,那么它离线计算的空间复杂度是$ O(F(M+N))$ ,迭代 S次则时间复杂度为\(O(K * F * S)\)。当 M(用户数量)和 N*(物品数量)很大时LFM相对于ItemCF和UserCF可以很好地节省离线计算的内存,在时间复杂度由于LFM会多次迭代上所以和ItemCF、UserCF没有质的差别。
同时,遗憾的是,LFM无法进行在线实时推荐,即当用户有了新的行为后,他的推荐列表不会发生变化。而从 LFM的预测公式可以看到, LFM 在给用户生成推荐列表时,需要计算用户对所有物品的兴趣权重,然后排名,返回权重最大的 N 个物品。那么,在物品数很多时,这一过程的时间复杂度非常高,可达 \(O(M*N*F)\) 。因此, LFM 不太适合用于物品数非常庞大的系统,如果要用,我们也需要一个比较快的算法给用户先计算一个比较小的候选列表,然后再用LFM 重新排名。另一方面,LFM 在生成一个用户推荐列表时速度太慢,因此不能在线实时计算,而需要离线将所有用户的推荐结果事先计算好存储在数据库中。
参考:
- 协同过滤算法总结---by刘建平
- 推荐系统实战---项亮
- 推荐算法-基于矩阵分解的CF算法实现(二):BiasSvd
(欢迎转载,转载请注明出处。欢迎沟通交流: losstie@outlook.com)
推荐算法之用矩阵分解做协调过滤——LFM模型的更多相关文章
- ML.NET 示例:推荐之One Class 矩阵分解
写在前面 准备近期将微软的machinelearning-samples翻译成中文,水平有限,如有错漏,请大家多多指正. 如果有朋友对此感兴趣,可以加入我:https://github.com/fei ...
- SVD++:推荐系统的基于矩阵分解的协同过滤算法的提高
1.背景知识 在讲SVD++之前,我还是想先回到基于物品相似的协同过滤算法.这个算法基本思想是找出一个用户有过正反馈的物品的相似的物品来给其作为推荐.其公式为:
- Mahout分布式运行实例:基于矩阵分解的协同过滤评分系统(一个命令实现文件格式的转换)
Apr 08, 2014 Categories in tutorial tagged with Mahout hadoop 协同过滤 Joe Jiang 前言:之前配置Mahout时测试过一个简 ...
- 【RS】List-wise learning to rank with matrix factorization for collaborative filtering - 结合列表启发排序和矩阵分解的协同过滤
[论文标题]List-wise learning to rank with matrix factorization for collaborative filtering (RecSys '10 ...
- 用Spark学习矩阵分解推荐算法
在矩阵分解在协同过滤推荐算法中的应用中,我们对矩阵分解在推荐算法中的应用原理做了总结,这里我们就从实践的角度来用Spark学习矩阵分解推荐算法. 1. Spark推荐算法概述 在Spark MLlib ...
- 机器学习笔记7:矩阵分解Recommender.Matrix.Factorization
目录 1矩阵分解概述 1.1用在什么地方 1.2推荐的原理 2矩阵分解的原理 2.1目标函数 2.2 损失函数 2.3 通过梯度下降的方法求得结果 3 代码实现 参考地址: 贪心学院:https:// ...
- SparkMLlib—协同过滤推荐算法,电影推荐系统,物品喜好推荐
SparkMLlib-协同过滤推荐算法,电影推荐系统,物品喜好推荐 一.协同过滤 1.1 显示vs隐式反馈 1.2 实例介绍 1.2.1 数据说明 评分数据说明(ratings.data) 用户信息( ...
- SimRank协同过滤推荐算法
在协同过滤推荐算法总结中,我们讲到了用图模型做协同过滤的方法,包括SimRank系列算法和马尔科夫链系列算法.现在我们就对SimRank算法在推荐系统的应用做一个总结. 1. SimRank推荐算法的 ...
- 全文搜索(A-2)-推荐算法
一般来说推荐算法分为两类. 基于内容过滤的推荐: 基于协同过滤的推荐: 基于内容过滤的推荐,基于特征码描述项目. 协同过滤算法的设计基于一个假设,“和目标用户相似度高的用户,其感兴趣的物品目标用户也会 ...
随机推荐
- ESP8266开发之旅 基础篇② 如何安装ESP8266的Arduino开发环境
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...
- python问题:IndentationError:expected an indented block
Python语言是一款对缩进非常敏感的语言,给很多初学者带来了困惑,即便是很有经验的Python程序员,也可能陷入陷阱当中.最常见的情况是tab和空格的混用会导致错误,或者缩进不对,而这是用肉眼无法分 ...
- 百万年薪python之路 -- 基础数据类型的补充
基础数据类型的补充 str: 首字母大写 name = 'alexdasx' new_name = name.capitalize() print(new_name) 通过元素查找下标 从左到右 只查 ...
- js检测页面上一个元素是否已经滚动到了屏幕的可视区域内
应用场景:只要页面加载了,其中在页面中出现的li就向控制台输出第几个发送请求:在本次加载的页面中,再将滚动条滚回前边的li,不再向控制台输出东西,也就是说已经显示过的li,不再向控制台输出东西. &l ...
- java Int数据工具类
1.在使用tcp协议传输数据时,使用到的 Int 数据的工具类方法 //将 Int 数据转换成字节数组 public static byte[] intToByteArray(int data){ b ...
- Yii 1.1.x 单元测试
代码若不整洁,只会越来越糟糕:代码写不好,公司要黄是迟早. Yii 的应用有两种,下面记录这两种应用的单元测试方法 webApplication consoleApplication 在protect ...
- 数据结构(三十三)最小生成树(Prim、Kruskal)
一.最小生成树的定义 一个连通图的生成树是一个极小的连通子图,它含有图中全部的顶点,但只有足以构成一棵树的n-1条边. 在一个网的所有生成树中,权值总和最小的生成树称为最小代价生成树(Minimum ...
- POJ2431 优先队列+贪心 - biaobiao88
以下代码可对结构体数组中的元素进行排序,也差不多算是一个小小的模板了吧 #include<iostream> #include<algorithm> using namespa ...
- 一文让你彻底了解大数据实时计算引擎 Flink
前言 在上一篇文章 你公司到底需不需要引入实时计算引擎? 中我讲解了日常中常见的实时需求,然后分析了这些需求的实现方式,接着对比了实时计算和离线计算.随着这些年大数据的飞速发展,也出现了不少计算的框架 ...
- Centos 7修改hostname浅析
之前写过一篇博客"深入理解Linux修改hostname",里面总结了RHEL 5.7下面如何修改hostname,当然这篇博客的内容其实也适用于CentOS 6,但是自CentO ...