在协同过滤推荐算法总结中,咱们讲到了用矩阵分解作协同过滤是普遍使用的方法,这里就对矩阵分解在协同过滤推荐算法中的应用作一个总结。(过年前最后一篇!祝你们新年快乐!明年的目标是写120篇机器学习,深度学习和NLP相关的文章)html
在推荐系统中,咱们经常遇到的问题是这样的,咱们有不少用户和物品,也有少部分用户对少部分物品的评分,咱们但愿预测目标用户对其余未评分物品的评分,进而将评分高的物品推荐给目标用户。好比下面的用户物品评分表:算法
用户\物品 | 物品1 | 物品2 | 物品3 | 物品4 | 物品5 | 物品6 | 物品7 |
用户1 | 3 | 5 | 1 | ||||
用户2 | 2 | 4 | |||||
用户3 | 4 | ||||||
用户4 | 2 | 1 | |||||
用户5 | 1 | 4 |
对于每一个用户,咱们但愿较准确的预测出用户对未评分物品的评分。对于这个问题咱们有不少解决方法,本文咱们关注于用矩阵分解的方法来作。若是将m个用户和n个物品对应的评分看作一个矩阵$M$,咱们但愿经过矩阵分解来解决这个问题。编程
说道矩阵分解,咱们首先想到的就是奇异值分解SVD。在奇异值分解(SVD)原理与在降维中的应用中,咱们对SVD原理作了总结。若是你们对SVD不熟悉的话,能够翻看该文。机器学习
此时能够将这个用户物品对应的$m \times n$矩阵$M$进行SVD分解,并经过选择部分较大的一些奇异值来同时进行降维,也就是说矩阵$M$此时分解为:$$M_{m \times n}=U_{m \times k}\Sigma_{k \times k}V_{k \times n}^T $$ 函数
其中k是矩阵$M$中较大的部分奇异值的个数,通常会远远的小于用户数和物品树。若是咱们要预测第i个用户对第j个物品的评分$m_{ij}$,则只须要计算$u_i^T\Sigma v_j$便可。经过这种方法,咱们能够将评分表里面全部没有评分的位置获得一个预测评分。经过找到最高的若干个评分对应的物品推荐给用户。post
能够看出这种方法简单直接,彷佛颇有吸引力。可是有一个很大的问题咱们忽略了,就是SVD分解要求矩阵是稠密的,也就是说矩阵的全部位置不能有空白。有空白时咱们的$M$是无法直接去SVD分解的。你们会说,若是这个矩阵是稠密的,那不就是说咱们都已经找到全部用户物品的评分了嘛,那还要SVD干吗! 的确,这是一个问题,传统SVD采用的方法是对评分矩阵中的缺失值进行简单的补全,好比用全局平均值或者用用户物品平均值补全,获得补全后的矩阵。接着能够用SVD分解并降维。学习
虽然有了上面的补全策略,咱们的传统SVD在推荐算法上仍是较难使用。由于咱们的用户数和物品通常都是超级大,随便就成千上万了。这么大一个矩阵作SVD分解是很是耗时的。那么有没有简化版的矩阵分解能够用呢?咱们下面来看看实际能够用于推荐系统的矩阵分解。优化
FunkSVD是在传统SVD面临计算效率问题时提出来的,既然将一个矩阵作SVD分解成3个矩阵很耗时,同时还面临稀疏的问题,那么咱们能不能避开稀疏问题,同时只分解成两个矩阵呢?也就是说,如今指望咱们的矩阵$M$这样进行分解:$$M_{m \times n}=P_{m \times k}^TQ_{k \times n}$$htm
咱们知道SVD分解已经很成熟了,可是FunkSVD如何将矩阵$M$分解为$P$和$Q$呢?这里采用了线性回归的思想。咱们的目标是让用户的评分和用矩阵乘积获得的评分残差尽量的小,也就是说,能够用均方差做为损失函数,来寻找最终的$P$和$Q$。blog
对于某一个用户评分$m_{ij}$,若是用FunkSVD进行矩阵分解,则对应的表示为$q_j^Tp_i$,采用均方差作为损失函数,则咱们指望$(m_{ij}-q_j^Tp_i)^2$尽量的小,若是考虑全部的物品和样本的组合,则咱们指望最小化下式:$$\sum\limits_{i,j}(m_{ij}-q_j^Tp_i)^2$$
只要咱们可以最小化上面的式子,并求出极值所对应的$p_i, q_j$,则咱们最终能够获得矩阵$P$和$Q$,那么对于任意矩阵$M$任意一个空白评分的位置,咱们能够经过$q_j^Tp_i$计算预测评分。很漂亮的方法!
固然,在实际应用中,咱们为了防止过拟合,会加入一个L2的正则化项,所以正式的FunkSVD的优化目标函数$J(p,q)$是这样的:$$\underbrace{arg\;min}_{p_i,q_j}\;\sum\limits_{i,j}(m_{ij}-q_j^Tp_i)^2 + \lambda(||p_i||_2^2 + ||q_j||_2^2 ) $$
其中$\lambda$为正则化系数,须要调参。对于这个优化问题,咱们通常经过梯度降低法来进行优化获得结果。
将上式分别对$p_i, q_j$求导咱们获得:$$\frac{\partial J}{\partial p_i} = -2(m_{ij}-q_j^Tp_i)q_j + 2\lambda p_i$$$$\frac{\partial J}{\partial q_j} = -2(m_{ij}-q_j^Tp_i)p_i + 2\lambda q_j$$
则在梯度降低法迭代时,$p_i, q_j$的迭代公式为: $$p_i = p_i + \alpha((m_{ij}-q_j^Tp_i)q_j - \lambda p_i)$$$$q_j =q_j + \alpha((m_{ij}-q_j^Tp_i)p_i - \lambda q_j)$$
经过迭代咱们最终能够获得$P$和$Q$,进而用于推荐。FunkSVD算法虽然思想很简单,可是在实际应用中效果很是好,这真是验证了大道至简。
在FunkSVD算法火爆以后,出现了不少FunkSVD的改进版算法。其中BiasSVD算是改进的比较成功的一种算法。BiasSVD假设评分系统包括三部分的偏置因素:一些和用户物品无关的评分因素,用户有一些和物品无关的评分因素,称为用户偏置项。而物品也有一些和用户无关的评分因素,称为物品偏置项。这其实很好理解。好比一个垃圾山寨货评分不可能高,自带这种烂属性的物品因为这个因素会直接致使用户评分低,与用户无关。
假设评分系统平均分为$\mu$,第i个用户的用户偏置项为$b_i$,而第j个物品的物品偏置项为$b_j$,则加入了偏置项之后的优化目标函数$J(p,q)$是这样的$$\underbrace{arg\;min}_{p_i,q_j}\;\sum\limits_{i,j}(m_{ij}-\mu-b_i-b_j-q_j^Tp_i)^2 + \lambda(||p_i||_2^2 + ||q_j||_2^2 + ||b_i||_2^2 + ||b_j||_2^2) $$
这个优化目标也能够采用梯度降低法求解。和FunkSVD不一样的是,此时咱们多了两个偏执项$b_i,b_j$,,$p_i, q_j$的迭代公式和FunkSVD相似,只是每一步的梯度导数稍有不一样而已,这里就不给出了。而$b_i,b_j$通常能够初始设置为0,而后参与迭代。这里给出$b_i,b_j$的迭代方法$$b_i = b_i + \alpha(m_{ij}-\mu-b_i-b_j-q_j^Tp_i -\lambda b_i)$$$$b_j = b_j + \alpha(m_{ij}-\mu-b_i-b_j-q_j^Tp_i -\lambda b_j)$$
经过迭代咱们最终能够获得$P$和$Q$,进而用于推荐。BiasSVD增长了一些额外因素的考虑,所以在某些场景会比FunkSVD表现好。
SVD++算法在BiasSVD算法上进一步作了加强,这里它增长考虑用户的隐式反馈。好吧,一个简单漂亮的FunkSVD硬是被越改越复杂。
对于某一个用户i,它提供了隐式反馈的物品集合定义为$N(i)$, 这个用户对某个物品j对应的隐式反馈修正的评分值为$c_{ij}$, 那么该用户全部的评分修正值为$\sum\limits_{s \in N(i)}c_{sj}$。通常咱们将它表示为用$q_j^Ty_s$形式,则加入了隐式反馈项之后的优化目标函数$J(p,q)$是这样的:$$\underbrace{arg\;min}_{p_i,q_j}\;\sum\limits_{i,j}(m_{ij}-\mu-b_i-b_j-q_j^Tp_i - q_j^T|N(i)|^{-1/2}\sum\limits_{s \in N(i)}y_{s})^2+ \lambda(||p_i||_2^2 + ||q_j||_2^2 + ||b_i||_2^2 + ||b_j||_2^2 + \sum\limits_{s \in N(i)}||y_{s}||_2^2) $$
其中,引入$|N(i)|^{-1/2}$是为了消除不一样|N(i)|个数引发的差别。式子够长的,不过须要考虑用户的隐式反馈时,使用SVD++仍是不错的选择。
FunkSVD将矩阵分解用于推荐方法推到了新的高度,在实际应用中使用也是很是普遍。固然矩阵分解方法也在不停的进步,目前张量分解和分解机方法是矩阵分解推荐方法从此的一个趋势。
对于矩阵分解用于推荐方法自己来讲,它容易编程实现,实现复杂度低,预测效果也好,同时还能保持扩展性。这些都是它宝贵的优势。固然,矩阵分解方法有时候解释性仍是没有基于几率的逻辑回归之类的推荐算法好,不过这也不影响它的流形程度。小的推荐系统用矩阵分解应该是一个不错的选择。大型的话,则矩阵分解比起如今的深度学习的一些方法不占优点。
(欢迎转载,转载请注明出处。欢迎沟通交流: liujianping-ok@163.com)