推荐算法&评分预测问题
参考书本: 项亮, 推荐系统实践. 2012
本文系阅读笔记
实际系统-topN问题
推荐系统各种研究比赛-评分预测问题。
评分预测问题最基本数据集就是用户评分数据集。(u,i,r)
用户u给物品i评了r分。
评分预测问题是如何通过已知的用户历史记录评分预测未知的用户评分记录。
离线实验方法
一般可以用均方根误差RMSE度量预测的精度:
评分预测的目的就是找到最好的模型最小化测试集的RMSE
【即预测数据的平均误差最小】
划分训练集和测试集的方法:
如果和时间没有关系--可以随机
如果和时间有关系--用户的旧行为为训练集,新行为为测试集。
Netflix 通过如下方式划分数据集,首先将每个用户的评分记录按照从早到晚进行排序,然后将用户最后 10%的评分记录作为测试集,前 90% 的评分记录作为训练集。
评分预测方法
平均值
-
全局平均值
它的定义为训练集中所有评分记录的评分平均值。
而最终的预测函数可以直接定义为
-
用户评分平均值
用户u的评分平均值定义为用户u在训练集中所有评分的平均值。
而最终的预测函数可以直接定义为
-
物品评分平均值
物品i的评分平均值定义为物品i在训练集中所有评分的平均值:
而最终的预测函数可以直接定义为
-
用户分类对物品分类的平均值
假设有两个分类函数,一个是用户分类函数,一个是物品分类函数。定义了用户u所属的类,定义了物品i所属的类。那么,我们可以利用训练集中同类用户对同类物品评分的平均值预测用户对物品的评分,即:
如果定义=0,=0,那么 就是全局平均值。
如果定义 =u, =0,那么就是用户评分平均值。
如果定义=0,=i ,那么 就是物品评分平均值。
除了这 3 种特殊的平均值,在用户评分数据上还可以定义很多不同的分类函数。
用户和物品的平均分 对于一个用户,可以计算他的评分平均分。然后将所有用户按照评分平均分从小到大排序,并将用户按照平均分平均分成 N 类。物品也可以用同样的方式分类。
用户活跃度和物品流行度 对于一个用户,将他评分的物品数量定义为他的活跃度。得到用户活跃度之后,可以将用户通过活跃度从小到大排序,然后平均分为 N 类。物品的流行度定义为给物品评分的用户数目,物品也可以按照流行度均匀分成 N 类。[计算类类平均值的方法代码见书]
在这段代码中, user_cluster.GetGroup 函数接收一个用户 ID ,然后根据一定的算法返回用户的类别。 item_cluster.GetGroup 函数接收一个物品的 ID ,然后根据一定的算法返回物品的类别。 total[gu][gi]/count[gu][gi] 记录了第 gu 类用户给第 gi 类物品评分的平均分。上文提到, user_cluster 和 item_cluster 有很多不同的定义方式。
【详细看书】
基于邻域的方法
基于用户的邻域算法和基于物品的邻域算法都可以应用到评分预测中。
基于用户的邻域算法认为预测一个用户对一个物品的评分,需要参考和这个用户兴趣相似的用户对该物品的评分。
基于物品的邻域算法在预测用户 u 对物品 i 的评分时,会参考用户 u 对和物品 i 相似的其他物品的评分。
用到了皮尔逊系数。
隐语义模型和矩阵分解模型
在推荐系统领域,提的最多的就是潜语义模型和矩阵分解模型。其实,这两个名词说的是一回事,就是如何通过降维的方法将评分矩阵补全。
用户的评分行为可以表示成一个评分矩阵 R ,其中 R [ u ][ i ] 就是用户 u 对物品 i 的评分。但是,用户不会对所有的物品评分,所以这个矩阵里有很多元素都是空的,这些空的元素称为缺失值( missing value )。因此,评分预测从某种意义上说就是填空,如果一个用户对一个物品没有评过分,那么推荐系统就要预测这个用户是否是否会对这个物品评分以及会评几分。
SVD分解
一般认为,如果补全后矩阵的特征值和补全之前矩阵的特征值相差不大,就算是扰动比较小。所以,最早的矩阵分解模型就是从数学上的 SVD (奇异值分解)开始的。
降维分解。
SVD 分解是早期推荐系统研究常用的矩阵分解方法,不过该方法具有以下缺点,因此很难在
实际系统中应用。
该方法首先需要用一个简单的方法补全稀疏评分矩阵。一般来说,推荐系统中的评分矩阵是非常稀疏的,一般都有 95% 以上的元素是缺失的。而一旦补全,评分矩阵就会变成一个稠密矩阵,从而使评分矩阵的存储需要非常大的空间,这种空间的需求在实际系统中是不可能接受的。
该方法依赖的 SVD 分解方法的计算复杂度很高,特别是在稠密的大规模矩阵上更是非常慢。一般来说,这里的 SVD 分解用于 1000 维以上的矩阵就已经非常慢了,而实际系统动辄是上千万的用户和几百万的物品,所以这一方法无法使用。如果仔细研究关于这一方法的论文可以发现,实验都是在几百个用户、几百个物品的数据集上进行的。
Simon Funk SVD
Simon Funk 提出的矩阵分解方法后来被 Netflix Prize 的冠军 Koren 称为 Latent Factor Model (简称为 LFM )
令
那么, Simon Funk 的思想很简单:可以直接通过训练集中的观察值利用最小化 RMSE 学习 P 、 Q 矩阵。
【于是得到损失函数】
为了防止过拟合,再加上正则化。然后利用梯度下降求参数。
是学习速率( learning rate ),它的取值需要通过反复实验获得。
【这块可以看书,和机器学习推导比较像】
LFM 提出之后获得了很大的成功,后来很多著名的模型都是通过对 LFM 修修补补获得的,下面的各节将分别介绍一下改进 LFM 的各种方法。这些改进有些是对模型的改进,有些是将新的数据引入到模型当中。
加入偏置项后的LFM
μ:训练集中所有记录的评分的全局平均数。在不同网站中,因为网站定位和销售的物品不同,网站的整体评分分布也会显示出一些差异。比如有些网站中的用户就是喜欢打高分,而另一些网站的用户就是喜欢打低分。而全局平均数可以表示网站本身对用户评分的影响。
用户评分相对所有平均分的误差(有的用户苛刻有的用户宽容。)
物体平均分相对均分偏差。物体好坏。
其中要通过机器学习训练出来。
考虑邻域影响的LFM SVD++
前面的 LFM 模型中并没有显式地考虑用户的历史行为对用户评分预测的影响。为此, Koren在 Netflix Prize 比赛中提出了一个模型,将用户历史评分的物品加入到了 LFM 模型中, Koren 将该模型称为 SVD++ 。
[代码看书]
SVD++就是加入了很多边缘信息,在SVD的基础上引入了隐式反馈。
关于公式推导及更多信息参见:
https://www.jianshu.com/p/f06860717c9e
https://www.cnblogs.com/Xnice/p/4522671.html
加入时间信息
利用时间信息的方法也主要分成两种,一种是将时间信息应用到基于邻域的模型中,另一种是将时间信息应用到矩阵分解模型中。下面将分别介绍这两种算法。
基于邻域的模型
因为 Netflix Prize 数据集中用户数目太大,所以基于用户的邻域模型很少被使用,主要是因为存储用户相似度矩阵非常困难。因此,本节主要讨论如何将时间信息融合到基于物品的邻域模型中。
也是用一个时间函数。随时间离现在越远,物品影响力越小。
【公式太复杂不想敲了,看书吧】
TitemCF
基于矩阵分解的模型
在引入时间信息后,用户评分矩阵不再是一个二维矩阵,而是变成了一个三维矩阵。不过,我们可以仿照分解二维矩阵的方式对三维矩阵进行分解。
TSVD
【公式见书】
模型融合
模型级联融合
假设已经有一个预测器,对于每个用户 — 物品对 (u, i) 都给出预测值,那么可以在这个预测器的基础上设计下一个预测器来最小化损失函数:
级联融合很像 Adaboost 算法。和 Adaboost 算法类似,该方法每次产生一个新模型,按照一定的参数加到旧模型上去,从而使训练集误差最小化。不同的是,这里每次生成新模型时并不对样本集采样,针对那些预测错的样本,而是每次都还是利用全样本集进行预测,但每次使用的模型都有区别。
一般来说,级联融合的方法都用于简单的预测器,比如前面提到的平均值预测器。
模型加权融合
假设我们有 K 个不同的预测器{},本节主要讨论如何将它们融合起来获得最低的预测误差。
最简单的融合算法就是线性融合,即最终的预测器是这 K 个预测器的线性加权。
因此,在模型融合时一般采用如下方法。
假设数据集已经被分为了训练集 A 和测试集 B ,那么首先需要将训练集 A 按照相同的分割方法分为 A1 和 A2 ,其中 A2 的生成方法和 B 的生成方法一致,且大小相似。
在 A1 上训练 K 个不同的预测器,在 A2 上作出预测。因为我们知道 A2 上的真实评分值,所以可以在 A2 上利用最小二乘法, 计算出线性融合系数 。
在 A 上训练 K 个不同的预测器,在 B 上作出预测,并且将这 K 个预测器在 B 上的预测结果按照已经得到的线性融合系数加权融合,以得到最终的预测结果。
除了线性融合,还有很多复杂的融合方法,比如利用人工神经网络的融合算法。其实,模型融合问题就是一个典型的回归问题,因此所有的回归算法都可以用于模型融合。