This commit is contained in:
louzefeng
2024-07-11 05:50:32 +00:00
parent bf99793fd0
commit d3828a7aee
6071 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
<audio id="audio" title="10 | 那些在Netflix Prize中大放异彩的推荐算法" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/04/0b/0472b66e70ddeafb35d222ec959ca20b.mp3"></audio>
早在前几篇务虚的文章中,我就和你聊过了推荐系统中的经典问题,其中有一类就是评分预测。
让我摸着自己的良心说,评分预测问题只是很典型,其实并不大众,毕竟在实际的应用中,评分数据很难收集到,属于典型的精英问题;与之相对的另一类问题行为预测,才是平民级推荐问题,处处可见。
## 缘起
评分预测问题之所以“虽然小众却十分重要”,这一点得益于十多年前 Netflix Prize 的那一百万美元的悬赏效应。
公元2006年10月2号对于很多人来说这只是平凡了无新意的一天但对于推荐系统从业者来说这是不得了的一天美国著名的光盘租赁商 Netflix 突然广发英雄帖放下“豪”言这个就是土豪的“豪”凡是能在他们现有推荐系统基础上把均方根误差降低10%的大侠可以瓜分100万美元。消息一出群贤毕至。
Netflix放出的比赛数据正是评分数据推荐系统的问题模式也是评分预测也就是为什么说评价标准是均方根误差了。
这一评分预测问题在一百万美元的加持下催生出无数推荐算法横空出世其中最为著名的就是一系列矩阵分解模型而最最著名的模型就是SVD以及其各种变体。这些模型后来也经受了时间检验在实际应用中得到了不同程度的开枝散叶。
今天我就来和你细聊一下矩阵分解SVD及其最有名的变种算法。
## 矩阵分解
### 为什么要矩阵分解
聪明的你也许会问,好好的近邻模型,一会儿基于用户,一会儿基于物品,感觉也能很酷炫地解决问题呀,为什么还要来矩阵分解呢?
刨除不这么做就拿不到那一百万的不重要因素之外,矩阵分解确实可以解决一些近邻模型无法解决的问题。
我们都是读书人,从不在背后说模型的坏话,这里可以非常坦诚地说几点近邻模型的问题:
1. 物品之间存在相关性,信息量并不随着向量维度增加而线性增加;
1. 矩阵元素稀疏,计算结果不稳定,增减一个向量维度,导致近邻结果差异很大的情况存在。
上述两个问题,在矩阵分解中可以得到解决。矩阵分解,直观上说来简单,就是把原来的大矩阵,近似分解成两个小矩阵的乘积,在实际推荐计算时不再使用大矩阵,而是使用分解得到的两个小矩阵。
具体说来就是假设用户物品的评分矩阵A是m乘以n维即一共有m个用户n个物品。我们选一个很小的数k这个k比m和n都小很多比如小两个数量级这样通过一套算法得到两个矩阵U和V矩阵U的维度是m乘以k矩阵V的维度是n乘以k。
这两个矩阵有什么要求呢要求就是通过下面这个公式复原矩阵A你可以点击文稿查看公式。
$$ U_{m\times{k}}V_{n\times{k}}^{T} \approx A_{m\times{n}}$$
类似这样的计算过程就是矩阵分解还有一个更常见的名字叫做SVD但是SVD和矩阵分解不能划等号因为除了SVD还有一些别的矩阵分解方法。
### 1 基础的SVD算法
值得一说的是SVD全称奇异值分解属于线性代数的知识;然而在推荐算法中实际上使用的并不是正统的奇异值分解,而是一个伪奇异值分解(具体伪在哪不是本文的重点)。
今天我介绍的SVD是由Netflix Prize中取得骄人成绩的Yehuda Koren提出的矩阵分解推荐算法。
按照顺序首先介绍基础的SVD算法然后是考虑偏置信息接着是超越评分矩阵增加多种输入最后是增加时间因素。好一个一个来。
前面已经从直观上大致说了矩阵分解是怎么回事这里再从物理意义上解释一遍。矩阵分解就是把用户和物品都映射到一个k维空间中这个k维空间不是我们直接看得到的也不一定具有非常好的可解释性每一个维度也没有名字所以常常叫做隐因子代表藏在直观的矩阵数据下面的。
每一个物品都得到一个向量q每一个用户也得到一个向量p。对于物品与它对应的向量q中的元素有正有负代表着这个物品背后暗藏的一些用户关注的因素。
对于用户与它对应的向量p中的元素也有正有负代表这个用户在若干因素上的偏好。物品被关注的因素和用户偏好的因素它们的数量和意义是一致的就是我们在矩阵分解之处人为指定的k。
举个例子用户u的向量是pu物品i的向量是qi那么要计算物品i推荐给用户u的推荐分数直接计算点积即可
$$ \hat{r}_{ui} = p_{u}q_{i}^{T}$$
看上去很简单难在哪呢难在如何得到每一个用户每一个物品的k维向量。这是一个机器学习问题。按照机器学习框架一般就是考虑两个核心要素
1. 损失函数;
1. 优化算法。
SVD的损失函数是这样定义的
$$ \min_{q^{* },p^{* } } \sum_{(u,i) \in \kappa }{(r_{ui} - p_{u}q_{i}^{T})^{2} + \lambda (||q_{i}||^{2} + ||p_{u}||^{2})} $$
理解SVD的参数学习过程并不是必须的如果你不是算法工程师的话不必深究这个过程。
由于这个公式略复杂,如果你正在听音频,就需要自己看一下图片。这个损失函数由两部分构成,加号前一部分控制着模型的偏差,加号后一部分控制着模型的方差。
前一部分就是:用分解后的矩阵预测分数,要和实际的用户评分之间误差越小越好。
后一部分就是:得到的隐因子向量要越简单越好,以控制这个模型的方差,换句话说,让它在真正执行推荐任务时发挥要稳定。这部分的概念对应机器学习中的过拟合,有兴趣可以深入了解。
整个SVD的学习过程就是
1. 准备好用户物品的评分矩阵,每一条评分数据看做一条训练样本;
1. 给分解后的U矩阵和V矩阵随机初始化元素值
1. 用U和V计算预测后的分数
1. 计算预测的分数和实际的分数误差;
1. 按照梯度下降的方向更新U和V中的元素值
1. 重复步骤3到5直到达到停止条件。
过程中提到的梯度下降是优化算法的一种,想深入了解可以参见任何一本机器学习的专著。
得到分解后的矩阵之后,实质上就是得到了每个用户和每个物品的隐因子向量,拿着这个向量再做推荐计算就简单了,哪里不会点哪里,意思就是拿着物品和用户两个向量,计算点积就是推荐分数了。
### 2 增加偏置信息
到现在你已经知道基础的SVD是怎么回事了。现在来多考虑一下实际情况试想一下有一些用户会给出偏高的评分比如标准宽松的用户有一些物品也会收到偏高的评分比如一些目标观众为铁粉的电影甚至有可能整个平台的全局评分就偏高。
所以原装的SVD就有了第一个变种把偏置信息抽出来的SVD。
一个用户给一个物品的评分会由四部分相加:
$$\hat{r}_{ui} = \mu + b_{i} + b_{u} + p_{u}q_{i}^{T} $$
从左至右分别代表:全局平均分、物品的评分偏置、用户评分的偏置、用户和物品之间的兴趣偏好。
针对前面三项偏置分数我在这里举个例子假如一个电影评分网站全局平均分是3分《肖申克的救赎》的平均分比全局平均分要高1分。
你是一个对电影非常严格的人你一般打分比平均分都要低0.5所以前三项从左到右分别就是31-0.5。如果简单的就靠这三项也可以给计算出一个你会给《肖申克的救赎》打的分数就是3.5。
增加了偏置信息的SVD模型目标函数稍有改变
<img src="https://static001.geekbang.org/resource/image/2c/85/2c6abb8736688e2ca315ef6fc7b03985.png" alt="" />
和基本的SVD相比要想学习两个参数用户偏置和物品偏置。学习的算法还是一样的。
### 3 增加历史行为
探讨完增加偏执信息的SVD后接着你再思考一个问题有的用户评分比较少。事实上这很常见相比沉默的大多数主动点评电影或者美食的用户是少数。
换句话说,显式反馈比隐式反馈少,那么能不能利用隐式反馈来弥补这一点呢?另外,再考虑多一点,对于用户的个人属性,比如性别等,是不是也可以加入到模型中来弥补冷启动的不足呢?
是的都是可以的在SVD中结合用户的隐式反馈行为和属性这套模型叫做SVD++。
先说隐式反馈怎么加入,方法是:除了假设评分矩阵中的物品有一个隐因子向量外,用户有过行为的物品集合也都有一个隐因子向量,维度是一样的。把用户操作过的物品隐因子向量加起来,用来表达用户的兴趣偏好。
类似的用户属性全都转换成0-1型的特征后对每一个特征也假设都存在一个同样维度的隐因子向量一个用户的所有属性对应的隐因子向量相加也代表了他的一些偏好。
综合两者SVD++的目标函数中,只需要把推荐分数预测部分稍作修改,原来的用户向量那部分增加了隐式反馈向量和用户属性向量:
$$ \hat{r}_{ui} = \mu + b_{i} + b_{u} + \<br />
(p_{u} + |N(u)|^{-0.5}\sum_{i\in{N(u)}}{x_{i}} + \sum_{a\in{A{u}}}{y_{a}})q_{i}^{T} $$<br />
(滑动查看完整公式)
学习算法依然不变只是要学习的参数多了两个向量x和y。一个是隐式反馈的物品向量另一个用户属性的向量。
这样一来,在用户没有评分时,也可以用他的隐式反馈和属性做出一定的预测。
## 4 考虑时间因素
截止到目前我们还没有正视过一个人性人是善变的。这个是一个广义的评价我们在进步也是在变化今天的我们和十年前的我们很可能不一样了。这是常态因此在SVD中考虑时间因素也变得顺理成章。
在SVD中考虑时间因素有几种做法
1. 对评分按照时间加权,让久远的评分更趋近平均值;
1. 对评分时间划分区间,不同的时间区间内分别学习出隐因子向量,使用时按照区间使用对应的隐因子向量来计算;
1. 对特殊的期间,如节日、周末等训练对应的隐因子向量。
## 总结
至此我们介绍了在Netflix Prize比赛中最为出众的模型SVD及其一些典型的改进。改进方案分别是
1. 考虑偏置信息;
1. 考虑隐式反馈和用户属性;
<li>考虑时间因素。<br />
其实Netflix Prize比赛上诞生了很多其他优秀的算法或者把一些已有的算法应用得到很好的效果比如受限玻尔兹曼机用来融合多个模型这个我会在后面的专栏文章中专门再讲。</li>
好了,最后我要给你留一个思考题,假如矩阵分解面对的数据不是评分数据,而是行为数据,那么今天讲到的损失函数是否依然有效呢?欢迎留言一起讨论。感谢你的收听,我们下次再见。
<img src="https://static001.geekbang.org/resource/image/87/b0/873b086966136189db14874181823fb0.jpg" alt="" />

View File

@@ -0,0 +1,137 @@
<audio id="audio" title="11 | Facebook是怎么为十亿人互相推荐好友的" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/cc/cf/cc12cef6a3c9089c85d15544239215cf.mp3"></audio>
上一篇中,我和你专门聊到了矩阵分解,在这篇文章的开始,我再为你回顾一下矩阵分解。
## 回顾矩阵分解
矩阵分解要将用户物品评分矩阵分解成两个小矩阵,一个矩阵是代表用户偏好的用户隐因子向量组成,另一个矩阵是代表物品语义主题的隐因子向量组成。
这两个小矩阵相乘后得到的矩阵维度和原来的用户物品评分矩阵一模一样。比如原来矩阵维度是m x n其中m是用户数量n是物品数量再假如分解后的隐因子向量是k个那么用户隐因子向量组成的矩阵就是m x k物品隐因子向量组成的矩阵就是n x k。
得到的这两个矩阵有这么几个特点:
1. 每个用户对应一个k维向量每个物品也对应一个k维向量就是所谓的隐因子向量因为是无中生有变出来的所以叫做“隐因子”
1. 两个矩阵相乘后,就得到了任何一个用户对任何一个物品的预测评分,具体这个评分靠不靠谱,那就是看功夫了。
所以矩阵分解,所做的事就是矩阵填充。那到底怎么填充呢,换句话也就是说两个小矩阵怎么得到呢?
按照机器学习的套路,就是使用优化算法求解下面这个损失函数:
$$ \min_{q^{* },p^{* } } \sum_{(u,i) \in \kappa }{(r_{ui} - p_{u}q_{i}^{T})^{2} + \lambda (||q_{i}||^{2} + ||p_{u}||^{2})} $$
这个公式依然由两部分构成:加号左边是误差平方和,加号右边是分解后参数的平方。
这种模式可以套在几乎所有的机器学习训练中:就是一个负责衡量模型准不准,另一个负责衡量模型稳不稳定。行话是这样说的:一个衡量模型的偏差,一个衡量模型的方差。偏差大的模型欠拟合,方差大的模型过拟合。
有了这个目标函数后就要用到优化算法找到能使它最小的参数。优化方法常用的选择有两个一个是随机梯度下降SGD另一个是交替最小二乘ALS
在实际应用中交替最小二乘更常用一些这也是社交巨头Facebook在他们的推荐系统中选择的主要矩阵分解方法今天我就专门聊一聊交替最小二乘求矩阵分解。
## 交替最小二乘原理 (ALS)
交替最小二乘的核心是交替什么意思呢你的任务是找到两个矩阵P和Q让它们相乘后约等于原矩阵R
$$ R_{m \times n} = P_{m \times k} \times Q^{T}_{n \times k} $$
难就难在P和Q两个都是未知的如果知道其中一个的话就可以按照线性代数标准解法求得比如如果知道了Q那么P就可以这样算
$$ P_{m \times k} = R_{m \times n} \times Q^{-1}_{n \times k}$$
也就是R矩阵乘以Q矩阵的逆矩阵就得到了结果。
反之知道了P再求Q也一样。交替最小二乘通过迭代的方式解决了这个鸡生蛋蛋生鸡的难题
1. 初始化随机矩阵Q里面的元素值
1. 把Q矩阵当做已知的直接用线性代数的方法求得矩阵P
1. 得到了矩阵P后把P当做已知的故技重施回去求解矩阵Q
1. 上面两个过程交替进行,一直到误差可以接受为止。
你看吧机器就是这么单纯善良先用一个假的结果让算法先运转起来然后不断迭代最终得到想要的结果。这和做互联网C2C平台的思路也一样告诉买家说快来这里我们是万能的什么都能买到
买家来了后又去告诉卖家们说:快来这里开店,我这里掌握了最多的剁手党。嗯,雪球就这样滚出来了。
交替最小二乘有这么几个好处:
1. 在交替的其中一步,也就是假设已知其中一个矩阵求解另一个时,要优化的参数是很容易并行化的;
1. 在不那么稀疏的数据集合上,交替最小二乘通常比随机梯度下降要更快地得到结果,事实上这一点就是我马上要说的,也就是关于隐式反馈的内容。
## 隐式反馈
矩阵分解算法,是为解决评分预测问题而生的,比如说,预测用户会给商品打几颗星,然后把用户可能打高星的商品推荐给用户,然而事实上却是,用户首先必须先去浏览商品,然后是购买,最后才可能打分。
相比“预测用户会打多少分”,“预测用户会不会去浏览”更加有意义,而且,用户浏览数据远远多于打分评价数据。也就是说,实际上推荐系统关注的是预测行为,行为也就是一再强调的隐式反馈。
那如何从解决评分预测问题转向解决预测行为上来呢这就是另一类问题了行话叫做One-Class。
这是什么意思呢如果把预测用户行为看成一个二分类问题猜用户会不会做某件事但实际上收集到的数据只有明确的一类用户干了某件事而用户明确“不干”某件事的数据却没有明确表达。所以这就是One-Class的由来One-Class数据也是隐式反馈的通常特点。
对隐式反馈的矩阵分解需要将交替最小二乘做一些改进改进后的算法叫做加权交替最小二乘Weighted-ALS。
这个加权要从哪说起?用户对物品的隐式反馈,通常是可以多次的,你有心心念念的衣服或者电子产品,但是刚刚剁完手的你正在吃土买不起,只能每天去看一眼。
这样一来,后台就记录了你查看过这件商品多少次,查看次数越多,就代表你越喜欢这个。也就是说,行为的次数是对行为的置信度反应,也就是所谓的加权。
加权交替最小二乘这样对待隐式反馈:
1. 如果用户对物品无隐式反馈则认为评分是0
1. 如果用户对物品有至少一次隐式反馈则认为评分是1次数作为该评分的置信度。
那现在的目标函数在原来的基础上变成这样:
$$ \min_{q^{* },p^{* } } \sum_{(u,i) \in \kappa }{c_{ui}(r_{ui} - p_{u}q_{i}^{T})^{2} + \lambda (||q_{i}||^{2} + ||p_{u}||^{2})} $$
多出来的Cui就是置信度在计算误差时考虑反馈次数次数越多就越可信。置信度一般也不是直接等于反馈次数根据一些经验置信度Cui这样计算
$$ c_{ui} = 1 + \alpha C $$
其中阿尔法是一个超参数需要调教默认值取40可以得到差不多的效果C就是次数了。
这里又引出另一个问题那些没有反馈的缺失值就是在我们的设定下取值为0的评分就非常多有两个原因导致在实际使用时要注意这个问题
1. 本身隐式反馈就只有正类别是确定的负类别是我们假设的你要知道One-Class并不是随便起的名字
1. 这会导致正负类别样本非常不平衡严重倾斜到0评分这边。
因此不能一股脑儿使用所有的缺失值作为负类别矩阵分解的初心就是要填充这些值如果都假设他们为0了那就忘记初心了。应对这个问题的做法就是负样本采样挑一部分缺失值作为负类别样本即可。
怎么挑?有两个方法:
1. 随机均匀采样和正类别一样多;
1. 按照物品的热门程度采样。
请允许我直接说结论,第一种不是很靠谱,第二种在实践中经过了检验。
还是回到初心来,你想一想,在理想情况下,什么样的样本最适合做负样本?
就是展示给用户了,他也知道这个物品的存在了,但就是没有对其作出任何反馈。问题就是很多时候不知道到底是用户没有意识到物品的存在呢,还是知道物品的存在而不感兴趣呢?
因此按照物品热门程度采样的思想就是:一个越热门的物品,用户越可能知道它的存在。那这种情况下,用户还没对它有反馈就表明:这很可能就是真正的负样本。
按照热门程度采样来构建负样本在实际中是一个很常用的技巧我之前和你提到的文本算法Word2Vec学习过程也用到了类似的负样本采样技巧。
## 推荐计算
在得到了分解后的矩阵后,相当于每个用户得到了隐因子向量,这是一个稠密向量,用于代表他的兴趣。同时每个物品也得到了一个稠密向量,代表它的语义或主题。而且可以认为这两者是一一对应的,用户的兴趣就是表现在物品的语义维度上的。
看上去让用户和物品的隐因子向量两两相乘计算点积就可以得到所有的推荐结果了。但是实际上复杂度还是很高尤其对于用户数量和物品数量都巨大的应用如Facebook就更不现实。于是Facebook提出了两个办法得到真正的推荐结果。
第一种利用一些专门设计的数据结构存储所有物品的隐因子向量从而实现通过一个用户向量可以返回最相似的K个物品。
Facebook给出了自己的开源实现Faiss类似的开源实现还有AnnoyKGraphNMSLIB。
其中Facebook开源的Faiss 和NMSLIBNon-Metric Space Library都用到了ball tree来存储物品向量。
如果需要动态增加新的物品向量到索引中推荐使用Faiss如果不是推荐使用NMSLIB或者KGraph。用户向量则可以存在内存数据中这样可以在用户访问时实时产生推荐结果。
第二种,就是拿着物品的隐因子向量先做聚类,海量的物品会减少为少量的聚类。然后再逐一计算用户和每个聚类中心的推荐分数,给用户推荐物品就变成了给用户推荐物品聚类。
得到给用户推荐的聚类后,再从每个聚类中挑选少许几个物品作为最终推荐结果。这样做的好处除了大大减小推荐计算量之外,还可以控制推荐结果的多样性,因为可以控制在每个类别中选择的物品数量。
## 总结
在真正的推荐系统的实际应用中,评分预测实际上场景很少,而且数据也很少。因此,相比预测评分,预测“用户会对物品干出什么事”,会更加有效。
然而这就需要对矩阵分解做一些改进加权交替最小二乘就是改进后的矩阵分解算法被Facebook采用在了他们的推荐系统中这篇文章里我也详细地解释了这一矩阵分解算法在落地时的步骤和注意事项。
其中我和你提到了针对One-Class这种数据集合一种常用的负样本构建方法是根据物品的热门程度采样你能想到还有哪些负样本构建方法吗欢迎留言一起讨论。感谢你的收听我们下次再见。
<img src="https://static001.geekbang.org/resource/image/87/b0/873b086966136189db14874181823fb0.jpg" alt="" />

View File

@@ -0,0 +1,131 @@
<audio id="audio" title="12 | 如果关注排序效果,那么这个模型可以帮到你" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/0f/c0/0feeb9af4afc8a4e09b7f9cef507dbc0.mp3"></audio>
矩阵分解在推荐系统中的地位非常崇高,恐怕本专栏介绍的其他算法模型都不能轻易地撼动它。
它既有协同过滤的血统,又有机器学习的基因,可以说是非常优秀了;但即便如此,传统的矩阵分解无论是在处理显式反馈,还是处理隐式反馈都让人颇有微词,这一点是为什么呢?
## 矩阵分解的不足
前面我讲过的两种矩阵分解,本质上都是在预测用户对一个物品的偏好程度,哪怕不是预测评分, 只是预测隐式反馈,也难逃这个事实,因为算法展现出来的目标函数就出卖了这一切。
得到这样的矩阵分解结果后,常常在实际使用时,又是用这个预测结果来排序。所以,从业者们口口声声宣称想要模型的预测误差最小化,结果绕了一大圈最后还是只想要一个好点的排序,让人不禁感叹:人心总是难测。
这种针对单个用户对单个物品的偏好程度进行预测得到结果后再排序的问题在排序学习中的行话叫做point-wise其中point意思就是只单独考虑每个物品每个物品像是空间中孤立的点一样。
与之相对的还有直接预测物品两两之间相对顺序的问题就叫做pair-wisepair顾名思义就是成对成双也许恐怕这类模型对单身的人士不是很友好。
前面讲的矩阵分解都属于point-wise模型。这类模型的尴尬是只能收集到正样本没有负样本于是认为缺失值就是负样本再以预测误差为评判标准去使劲逼近这些样本。逼近正样本没问题但是同时逼近的负样本只是缺失值而已还不知道真正呈现在用户面前到底是不喜欢还是喜欢呢
虽然这些模型采取了一些措施来规避这个问题,比如负样本采样,但是尴尬还是存在的,为了排序而绕路也是事实。
既然如此能不能直面问题采用pair-wise来看待矩阵分解呢当然能不然我也不会写出这一篇专栏文章了。
其实人在面对选择时总是倾向矮子中选高个子而不是真的在意身高到底是不是180因此更直接的推荐模型应该是能够较好地为用户排列出更好的物品相对顺序而非更精确的评分。
这个问题已经有可爱的从业者们提出了方法就是本文的主角贝叶斯个性化排序简称BPR模型。下面我就带你一探这个模型的究竟。
## 贝叶斯个性化排序
在前面的专栏文章中有一个词叫做均方根误差被我提过多次用于评价模型预测精准程度的。那么现在要关注的是相对排序用什么指标比较好呢答案是AUCAUC全称是Area Under Curve意思是曲线下的面积这里的曲线就是 ROC 曲线。
### AUC
但是,我不打算继续解释什么是 ROC 曲线了那是它的原始定义而我想跟你悄悄说的是另一件事AUC这个值在数学上等价于模型把关心的那一类样本排在其他样本前面的概率。最大是1完美结果而0.5就是随机排列0就是完美地全部排错。
听到这个等价的AUC解释你是不是眼前一亮这个非常适合用来评价模型的排序效果比如说得到一个推荐模型后按照它计算的分数能不能把用户真正想消费的物品排在前面这在模型上线前是可以用日志完全计算出来的。
AUC怎么计算呢一般步骤如下。
1. 用模型给样本计算推荐分数,比如样本都是用户和物品这样一对一对的,同时还包含了有无反馈的标识;
1. 得到打过分的样本每条样本保留两个信息第一个是分数第二个是0或者11表示用户消费过是正样本0表示没有是负样本
1. 按照分数对样本重新排序,降序排列;
1. 给每一个样本赋一个排序值,第一位 r1 = n第二位 r2 = n-1以此类推其中要注意如果几个样本分数一样需要将其排序值调整为他们的平均值
1. 最终按照下面这个公式计算就可以得到AUC值。
我在文稿中放了这个公式,你可以点击查看。
$$AUC = \frac{\sum_{i\in(样本)}{r_{i}} - \frac{M\times{(M+1)}}{2}}{M\times{N}}$$
这个公式看上去复杂,其实很简单,由两部分构成:
第一部分: 分母是所有我们关心的那类样本也就是正样本有M个以及其他样本有N个这两类样本相对排序总共的组合可能性是M x N
第二部分: 分子也不复杂原本是这样算的第一名的排序值是r1它在排序上不但比过了所有的负样本而且比过了自己以外的正样本。
但后者是自己人所以组合数要排除于是就有n - M种组合以此类推排序值为rM的就贡献了rM - 1把这些加起来就是分子。
关于AUC越接近1越好是肯定的但是并不是越接近0就越差最差的是接近0.5如果AUC很接近0的话只需要把模型预测的结果加个负号就能让AUC接近1具体的原因自行体会。
好了已经介绍完排序的评价指标了该主角出场了BPR模型它提出了一个优化准则和学习框架使得原来传统的矩阵分解放进来能够焕发第二春。
那到底BPR做了什么事情呢主要有三点
1. 一个样本构造方法;
1. 一个模型目标函数;
1. 一个模型学习框架。
通过这套三板斧,便可以脱离评分预测,来做专门优化排序的矩阵分解。下面详细说说这三板斧。
### 构造样本
前面介绍的矩阵分解,在训练时候处理的样本是:用户、物品、反馈,这样的三元组形式。
其中反馈又包含真实反馈和缺失值缺失值充当的是负样本职责。BPR则不同提出要关心的是物品之间对于用户的相对顺序于是构造的样本是用户、物品1、物品2、两个物品相对顺序这样的四元组形式其中“两个物品的相对顺序”取值是
1. 如果物品1是消费过的而物品2不是那么相对顺序取值为1是正样本
1. 如果物品1和物品2刚好相反则是负样本
1. 样本中不包含其他情况物品1和物品2都是消费过的或者都是没消费过的。
这样一来学习的数据是反应用户偏好的相对顺序而在使用时面对的是所有用户还没消费过的物品这些物品仍然可以在这样的模型下得到相对顺序这就比三元组point-wise样本要直观得多。
### 目标函数
现在,每条样本包含的是两个物品,样本预测目标是两个物品的相对顺序。按照机器学习的套路,就该要上目标函数了。
要看BPR怎么完成矩阵分解你依然需要像交替最小二乘那样的思想。
先假装矩阵分解结果已经有了,于是就计算出用户对于每个物品的推荐分数,只不过这个推荐分数可能并不满足均方根误差最小,而是满足物品相对排序最佳。
得到了用户和物品的推荐分数后就可以计算四元组的样本中物品1和物品2的分数差这个分数可能是正数也可能是负数也可能是0。
你和我当然都希望的情况是如果物品1和物品2相对顺序为1那么希望两者分数之差是个正数而且越大越好如果物品1和物品2的相对顺序是0则希望分数之差是负数且越小越好。
用个符号来表示这个差Xu12表示的是对用户u物品1和物品2的矩阵分解预测分数差。然后再用 sigmoid 函数把这个分数差压缩到0到1之间。
$$\Theta = \frac{1}{1 + e^{-(X_{u12})}}$$
也其实就是用这种方式预测了物品1排在物品2前面的似然概率所以最大化交叉熵就是目标函数了。
目标函数通常还要防止过拟合加上正则项正则项其实认为模型参数还有个先验概率这是贝叶斯学派的观点也是BPR这个名字中“贝叶斯”的来历。
BPR认为模型的先验概率符合正态分布对应到正则化方法就是L2正则这些都属于机器学习的内容这里不展开讲。
我来把目标函数写一下:
$$\prod_{u,i,j}{p(i&gt;_ {u}j | \theta)p(\theta)}$$
所有样本都计算模型参数先验概率p theta和似然概率的乘积最大化这个目标函数就能够得到分解后的矩阵参数其中theta就是分解后的矩阵参数。
最后说一句把这个目标函数化简和变形后和把AUC当成目标函数是非常相似的也正因为如此BPR模型的作者敢于宣称该模型是为AUC而生的。
### 训练方法
有了目标函数之后就要有请训练方法了。显然是老当益壮的梯度下降可以承担这件事梯度下降又有批量梯度和随机梯度下降两个选择前者收敛慢后者训练快却不稳定。因此BPR的作者使用了一个介于两者之间的训练方法结合重复抽样的梯度下降。具体来说是这样做的
1. 从全量样本中有放回地随机抽取一部分样本;
1. 用这部分样本,采用随机梯度下降优化目标函数,更新模型参数;
1. 重复步骤1直到满足停止条件。
这样,就得到了一个更符合推荐排序要求的矩阵分解模型了。
## 总结
今天是矩阵分解三篇的最后一篇,传统的矩阵分解,无论是隐式反馈还是显式反馈,都是希望更加精准地预测用户对单个物品的偏好,而实际上,如果能够预测用户对物品之间的相对偏好,则更加符合实际需求的直觉。
BPR就是这样一整套针对排序的推荐算法它事实上提出了一个优化准则和一个学习框架至于其中优化的对象是不是矩阵分解并不是它的重点。
但我在这里结合矩阵分解对其做了讲解同时还介绍了排序时最常用的评价指标AUC及其计算方法。
你在看了BPR算法针对矩阵分解的推荐计算过程之后试着想一想如果不是矩阵分解而是近邻模型那该怎么做欢迎留言给我一起聊聊。
<img src="https://static001.geekbang.org/resource/image/9f/93/9f92d45e88830b1713c10e320dca3293.jpg" alt="" />