mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2025-11-16 22:23:45 +08:00
mod
This commit is contained in:
192
极客时间专栏/推荐系统三十六式/原理篇 · MAB问题/16 | 简单却有效的Bandit算法.md
Normal file
192
极客时间专栏/推荐系统三十六式/原理篇 · MAB问题/16 | 简单却有效的Bandit算法.md
Normal file
@@ -0,0 +1,192 @@
|
||||
<audio id="audio" title="16 | 简单却有效的Bandit算法" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/5b/f0/5b8fb495bbf8b29a650419626595def0.mp3"></audio>
|
||||
|
||||
我在之前的文章中表达过,推荐系统的使命就是在建立用户和物品之间的连接。建立连接可以理解成:为用户匹配到最佳的物品;但也有另一个理解就是,在某个时间某个位置为用户选择最好的物品。
|
||||
|
||||
## 推荐就是选择
|
||||
|
||||
生活中,你我都会遇到很多要做选择的场景。上哪个大学,学什么专业,去哪家公司,中午吃什么等等。这些事情,都让选择困难症的我们头很大。头大在哪呢?主要是不知道每个选择会带来什么后果。
|
||||
|
||||
你仔细想一下,生活中为什么会害怕选择,究其原因是把每个选项看成独一无二的个体,一旦错过就不再来。推荐系统中一个一个单独的物品也如此,一旦选择呈现给用户,如果不能得到用户的青睐,就失去了一个展示机会。如果跳出来看这个问题,选择时不再聚焦到具体每个选项,而是去选择类别,这样压力是不是就小了很多?
|
||||
|
||||
比如说,把推荐选择具体物品,上升到选择策略。如果后台算法中有三种策略:按照内容相似推荐,按照相似好友推荐,按照热门推荐。每次选择一种策略,确定了策略后,再选择策略中的物品,这样两个步骤。
|
||||
|
||||
那么,是不是有办法来解决这个问题呢?当然有!那就是Bandit算法。
|
||||
|
||||
## MAB问题
|
||||
|
||||
Bandit算法来源于人民群众喜闻乐见的赌博学,它要解决的问题是这样的。
|
||||
|
||||
一个赌徒,要去摇老虎机,走进赌场一看,一排老虎机,外表一模一样,但是每个老虎机吐钱的概率可不一样,他不知道每个老虎机吐钱的概率分布是什么,那么想最大化收益该怎么整?
|
||||
|
||||
这就是多臂赌博机问题(Multi-armed bandit problem, K-armed bandit problem, MAB),简称MAB问题。有很多相似问题都属于MAB问题。
|
||||
|
||||
1. 假设一个用户对不同类别的内容感兴趣程度不同,当推荐系统初次见到这个用户时,怎么快速地知道他对每类内容的感兴趣程度?这也是推荐系统常常面对的冷启动问题。
|
||||
1. 假设系统中有若干广告库存物料,该给每个用户展示哪个广告,才能获得最大的点击收益,是不是每次都挑收益最好那个呢?
|
||||
1. 算法工程师又设计出了新的策略或者模型,如何既能知道它和旧模型相比谁更靠谱又对风险可控呢?
|
||||
|
||||
这些问题全都是关于选择的问题。只要是关于选择的问题,都可以简化成一个MAB问题。
|
||||
|
||||
我在前面的专栏中提过,推荐系统里面有两个顽疾,一个是冷启动,一个是探索利用问题,后者又称为EE问题:Exploit-Explore问题。针对这两个顽疾,Bandit算法可以入药。
|
||||
|
||||
冷启动问题好说,探索利用问题什么意思?
|
||||
|
||||
利用意思就是:比较确定的兴趣,当然要用啊。好比说我们已经挣到的钱,当然要花啊。
|
||||
|
||||
探索的意思就是:不断探索用户新的兴趣才行,不然很快就会出现一模一样的反复推荐。就好比我们虽然有一点钱可以花了,但是还得继续搬砖挣钱啊,要不然,花完了就要喝西北风了。
|
||||
|
||||
## Bandit算法
|
||||
|
||||
Bandit算法并不是指一个算法,而是一类算法。现在就来介绍一下Bandit算法家族怎么解决这类选择问题的。
|
||||
|
||||
首先,来定义一下,如何衡量选择的好坏?Bandit算法的思想是:看看选择会带来多少遗憾,遗憾越少越好。在MAB问题里,用来量化选择好坏的指标就是累计遗憾,计算公式如图所示。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/eb/62/ebae50f93e023a03e54ef057fc4c1062.png" alt="" />
|
||||
|
||||
简单描述一下这个公式。公式有两部分构成:一个是遗憾,一个是累积。求和符号内部就表示每次选择的遗憾多少。
|
||||
|
||||
Wopt就表示,每次都运气好,选择了最好的选择,该得到多少收益,WBi就表示每一次实际选择得到的收益,两者之差就是“遗憾”的量化,在T次选择后,就有了累积遗憾。
|
||||
|
||||
在这个公式中:为了简化MAB问题,每个臂的收益不是0,就是1,也就是伯努利收益。
|
||||
|
||||
这个公式可以用来对比不同Bandit算法的效果:对同样的多臂问题,用不同的Bandit算法模拟试验相同次数,比比看哪个Bandit算法的累积遗憾增长得慢,那就是效果较好的算法。
|
||||
|
||||
Bandit算法的套路就是:小心翼翼地试,越确定某个选择好,就多选择它,越确定某个选择差,就越来越少选择它。
|
||||
|
||||
如果某个选择实验次数较少,导致不确定好坏,那么就多给一些被选择机会,直到确定了它是金子还是石头。简单说就是,把选择的机会给“确定好的”和“还不确定的”。
|
||||
|
||||
Bandit算法中有几个关键元素:臂,回报,环境。
|
||||
|
||||
1. 臂:是每次选择的候选项,好比就是老虎机,有几个选项就有几个臂;
|
||||
1. 回报:就是选择一个臂之后得到的奖励,好比选择一个老虎机之后吐出来的金币;
|
||||
1. 环境:就是决定每个臂不同的那些因素,统称为环境。
|
||||
|
||||
将这个几个关键元素对应到推荐系统中来。
|
||||
|
||||
1. 臂:每次推荐要选择候选池,可能是具体物品,也可能是推荐策略,也可能是物品类别;
|
||||
1. 回报:用户是否对推荐结果喜欢,喜欢了就是正面的回报,没有买账就是负面回报或者零回报;
|
||||
1. 环境:推荐系统面临的这个用户就是不可捉摸的环境。
|
||||
|
||||
下面直接开始陈列出最常用的几个Bandit算法。
|
||||
|
||||
### 1.汤普森采样算法
|
||||
|
||||
第一个是汤普森采样算法。这个算法我个人很喜欢它,因为它只要一行代码就可以实现,并且数学的基础最简单。
|
||||
|
||||
简单介绍一下它的原理:假设每个臂是否产生收益,起决定作用的是背后有一个概率分布,产生收益的概率为p。
|
||||
|
||||
每个臂背后绑定了一个概率分布;每次做选择时,让每个臂的概率分布各自独立产生一个随机数,按照这个随机数排序,输出产生最大随机数那个臂对应的物品。听上去很简单,为什么这个随机数这么神奇?
|
||||
|
||||
关键在于每个臂背后的概率分布,是一个贝塔分布,先看看贝塔分布的样子:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/8f/c1/8f9e60416f8f32418ef7ba214ce961c1.png" alt="" />
|
||||
|
||||
贝塔分布有a和b两个参数。这两个参数决定了分布的形状和位置:
|
||||
|
||||
1. 当a+b值越大,分布曲线就越窄,分布就越集中,这样的结果就是产生的随机数会容易靠近中心位置;
|
||||
1. 当a/(a+b)的值越大,分布的中心位置越靠近1,反之就越靠近0,这样产生的随机数也相应第更容易靠近1或者0。
|
||||
|
||||
贝塔分布的这两个特点,可以把它分成三种情况:
|
||||
|
||||
1. 曲线很窄,而且靠近1;
|
||||
1. 曲线很窄,而且靠近0;
|
||||
1. 曲线很宽。
|
||||
|
||||
这和前面所讲的选择有什么关系呢?你把贝塔分布的a参数看成是推荐后得到用户点击的次数,把分布的b参数看成是没有得到用户点击的次数。按照这个对应,再来叙述一下汤普森采样的过程。
|
||||
|
||||
1. 取出每一个候选对应的参数a和b;
|
||||
1. 为每个候选用a和b作为参数,用贝塔分布产生一个随机数;
|
||||
1. 按照随机数排序,输出最大值对应的候选;
|
||||
1. 观察用户反馈,如果用户点击则将对应候选的a加1,否则b加1;
|
||||
|
||||
注意,实际上在推荐系统中,要为每一个用户都保存一套参数,比如候选有m个,用户有n个,那么就要保存2 * m * n 个参数。
|
||||
|
||||
汤普森采样为什么有效呢?解释一下。
|
||||
|
||||
1. 如果一个候选被选中的次数很多,也就是a+b很大了,它的分布会很窄,换句话说这个候选的收益已经非常确定了,用它产生随机数,基本上就在中心位置附近,接近平均收益。
|
||||
1. 如果一个候选不但a+b很大,即分布很窄,而且a/(a+b)也很大,接近1,那就确定这是个好的候选项,平均收益很好,每次选择很占优势,就进入利用阶段,反之则几乎再无出头之日。
|
||||
1. 如果一个候选的a+b很小,分布很宽,也就是没有被选择太多次,说明这个候选是好是坏还不太确定,那么用它产生随机数就有可能得到一个较大的随机数,在排序时被优先输出,这就起到了前面说的探索作用。
|
||||
|
||||
用Python实现汤普森采样就一行:
|
||||
|
||||
>
|
||||
choice = numpy.argmax(pymc.rbeta(1 + self.wins, 1 + self.trials - self.wins))
|
||||
|
||||
|
||||
### 2.UCB算法
|
||||
|
||||
第二个常用的Bandit算法就是UCB算法,UCB算法全称是Upper Confidence Bound,即置信区间上界。它也为每个臂评分,每次选择评分最高的候选臂输出,每次输出后观察用户反馈,回来更新候选臂的参数。
|
||||
|
||||
每个臂的评分公式为.<br />
|
||||
<img src="https://static001.geekbang.org/resource/image/bc/44/bc3cf903b267ea80309b56a44717b144.png" alt="" />
|
||||
|
||||
公式有两部分,加号前面是这个候选臂到目前的平均收益,反应了它的效果,后面的叫做Bonus,本质上是均值的标准差,反应了候选臂效果的不确定性,就是置信区间的上边界。t是目前的总选择次数,Tjt是每个臂被选择次数。
|
||||
|
||||
观察这个公式,如果一个候选的被选择次数很少,即Tjt很小,那么它的Bonus就会较大,在最后排序输出时有优势,这个Bonus反映了一个候选的收益置信区间宽度,Bonus越大,候选的平均收益置信区间越宽,越不确定,越需要更多的选择机会。
|
||||
|
||||
反之如果平均收益很大,就是说加号左边很大,也会在被选择时有优势。
|
||||
|
||||
这个评分公式也和汤普森采样是一样的思想:
|
||||
|
||||
1. 以每个候选的平均收益为基准线进行选择;
|
||||
1. 对于被选择次数不足的给予照顾;
|
||||
1. 选择倾向的是那些确定收益较好的候选。
|
||||
|
||||
### 3. Epsilon贪婪算法
|
||||
|
||||
这是一个朴素的算法,也很简单有效,思想有点类似模拟退火,做法如下。
|
||||
|
||||
<li>
|
||||
先选一个(0,1)之间较小的数,叫做Epsilon,也是这个算法名字来历。
|
||||
</li>
|
||||
<li>
|
||||
每次以概率Epsilon做一件事:所有候选臂中随机选一个,以1-Epsilon的概率去选择平均收益最大的那个臂。
|
||||
</li>
|
||||
|
||||
是不是简单粗暴?Epsilon的值可以控制对探索和利用的权衡程度。这个值越接近0,在探索上就越保守。
|
||||
|
||||
和这种做法相似,还有一个更朴素的做法:先试几次,等每个臂都统计到收益之后,就一直选均值最大那个臂。
|
||||
|
||||
### 4.效果对比
|
||||
|
||||
以上几个算法,可以简单用模拟试验的方式对比其效果,如图所示。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/7a/12/7aa810ba0419fefa12b2291f6f122612.png" alt="" />
|
||||
|
||||
横坐标是模拟次数增加,可以看成随着时间推移,纵坐标就是累积遗憾,越高说明搞砸的次数越多。在模拟后期,基本上各种算法优劣一目了然。从上到下分别是下面几种。
|
||||
|
||||
1. 完全随机:就是不顾用户反馈的做法。
|
||||
1. 朴素选择:就是认准一个效果好的,一直推。
|
||||
1. Epsilon贪婪算法:每次以小概率尝试新的,大概率选择效果好的。
|
||||
1. UCB:每次都会给予机会较少的候选一些倾向。
|
||||
1. 汤普森采样:用贝塔分布管理每一个候选的效果。
|
||||
|
||||
UCB算法和汤普森采样都显著优秀很多。
|
||||
|
||||
## 冷启动
|
||||
|
||||
我想,你已经想到了,推荐系统冷启动问题可以用Bandit算法来解决一部分。
|
||||
|
||||
大致思路如下:
|
||||
|
||||
<li>
|
||||
用分类或者Topic来表示每个用户兴趣,我们可以通过几次试验,来刻画出新用户心目中对每个Topic的感兴趣概率。
|
||||
</li>
|
||||
<li>
|
||||
这里,如果用户对某个Topic感兴趣,就表示我们得到了收益,如果推给了它不感兴趣的Topic,推荐系统就表示很遗憾(regret)了。
|
||||
</li>
|
||||
<li>
|
||||
当一个新用户来了,针对这个用户,我们用汤普森采样为每一个Topic采样一个随机数,排序后,输出采样值Top N 的推荐Item。注意,这里一次选择了Top N个候选臂。
|
||||
</li>
|
||||
<li>
|
||||
等着获取用户的反馈,没有反馈则更新对应Topic的b值,点击了则更新对应Topic的a值。
|
||||
</li>
|
||||
|
||||
## 总结
|
||||
|
||||
今天给你介绍了一种走一步看一步的推荐算法,叫做Bandit算法。Bandit算法把每个用户看成一个多变的环境,待推荐的物品就如同赌场里老虎机的摇臂,如果推荐了符合用户心目中喜欢的,就好比是从一台老虎机中摇出了金币一样。
|
||||
|
||||
今天重点介绍的Bandit算法有汤普森采样,UCB算法,Epsilon贪婪,并且用模拟的方式对比了它们的效果,汤普森采样以实现简单和效果显著而被人民群众爱戴,你需要时不妨首先试试它。
|
||||
|
||||
同时,这里留下一个问题给你,今天讲到的Bandit算法有哪些不足?欢迎留言和我一起讨论。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/87/b0/873b086966136189db14874181823fb0.jpg" alt="" />
|
||||
142
极客时间专栏/推荐系统三十六式/原理篇 · MAB问题/17 | 结合上下文信息的Bandit算法.md
Normal file
142
极客时间专栏/推荐系统三十六式/原理篇 · MAB问题/17 | 结合上下文信息的Bandit算法.md
Normal file
@@ -0,0 +1,142 @@
|
||||
<audio id="audio" title="17 | 结合上下文信息的Bandit算法" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/7e/e8/7ec39180507170be665a6eaa9d59a7e8.mp3"></audio>
|
||||
|
||||
上一篇文章我说到,Bandit算法用的是一种走一步看一步的思路,这一点看上去非常佛系,似乎一点都不如机器学习深度学习那样厚德载物,但是且慢下结论,先看看我在前面介绍的那几个Bandit算法。
|
||||
|
||||
## UCB回顾
|
||||
|
||||
这些Bandit算法,都有一个特点:完全没有使用候选臂的特征信息。特征可是机器学习的核心要素,也是机器学习泛化推广的依赖要素。
|
||||
|
||||
没有使用特征信息的Bandit算法,问题就在于只能对当前已有的这些候选臂进行选择,对于新加入的候选只能从0开始积累数据,而不能借助已有的候选泛化作用。
|
||||
|
||||
举个例子,假如有一个用户是鹿晗的粉丝,通过Bandit算法有两个鹿晗的广告得到展示,并得到了较好的收益。
|
||||
|
||||
那么对于一个新的广告,如果具有鹿晗这个特征,直觉上前两个鹿晗广告的收益信息可以泛化到当前新广告上,新广告就不是完全从0开始积累数据,而是有了一定的基础,这样的收敛会更快。
|
||||
|
||||
UCB和汤普森采样这两个Bandit算法在实际中表现很好。于是,前辈们就决定送UCB去深造一下,让它能够从候选臂的特征信息中学到一些知识。
|
||||
|
||||
UCB就是置信上边界的简称,所以UCB这个名字就反映了它的全部思想。置信区间可以简单直观地理解为不确定性的程度,区间越宽,越不确定,反之就很确定。
|
||||
|
||||
1. 每个候选的回报均值都有个置信区间,随着试验次数增加,置信区间会变窄,相当于逐渐确定了到底是回报丰厚还是亏了。
|
||||
1. 每次选择前,都根据已经试验的结果重新估计每个候选的均值及置信区间。
|
||||
1. 选择置信区间上界最大的那个候选。
|
||||
|
||||
“选择置信区间上界最大的那个候选”,这句话反映了几个意思:
|
||||
|
||||
1. 如果候选的收益置信区间很宽,相当于被选次数很少,还不确定,那么它会倾向于被多次选择,这个是算法冒风险的部分;
|
||||
1. 如果候选的置信区间很窄,相当于被选次数很多,比较确定其好坏了,那么均值大的倾向于被多次选择,这个是算法保守稳妥的部分;
|
||||
1. UCB是一种乐观冒险的算法,它每次选择前根据置信区间上界排序,反之如果是悲观保守的做法,可以选择置信区间下界排序。
|
||||
|
||||
## LinUCB
|
||||
|
||||
“Yahoo!”的科学家们在2010年基于UCB提出了LinUCB算法,它和传统的UCB算法相比,最大的改进就是加入了特征信息,每次估算每个候选的置信区间,不再仅仅是根据实验,而是根据特征信息来估算,这一点就非常的“机器学习”了。
|
||||
|
||||
在广告推荐领域,每一个选择的样本,由用户和物品一起构成,用户特征,物品特征,其他上下文特征共同表示出这个选择,把这些特征用来估计这个选择的预期收益和预期收益的置信区间,就是LinUCB要做的事情。
|
||||
|
||||
LinUCB算法做了一个假设:一个物品被选择后推送给一个用户,其收益和特征之间呈线性关系。在具体原理上,LinUCB有一个简单版本以及一个高级版本。简单版本其实就是让每一个候选臂之间完全互相无关,参数不共享。高级版本就是候选臂之间共享一部分参数。
|
||||
|
||||
先从简单版本讲起。
|
||||
|
||||
还是举个例子,假设现在两个用户,用户有一个特征就是性别,性别特征有两个维度,男,女。现在有四个商品要推荐给这两个用户,示意如下。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/ea/4b/eae9254fef3cdfc681247f58fa740b4b.png" alt="" />
|
||||
|
||||
两个用户就是Bandit算法要面对的上下文,表示成特征就是下面的样子。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/d4/ae/d47f7f976d7a0fd651f8f4be67f8aeae.png" alt="" />
|
||||
|
||||
每一次推荐时,用特征和每一个候选臂的参数去预估它的预期收益和置信区间。
|
||||
|
||||
$x_{i}\times\theta_{j}$,这就是给男性用户推荐剃须刀,给女性用户推荐口红,即使是新用户,也可以作出比随机猜测好的推荐,再观察用户是否会点击,用点击信息去更新那个被推荐了的候选臂的参数。
|
||||
|
||||
这里的例子还简化了一个地方,就是没有计算置信区间,这是UCB的精髓。下面来补上。
|
||||
|
||||
假如D是候选臂在m次被选择中积累的特征,相当于就是m条样本,特征维度是d,所以D是一个矩阵,维度是m x d。
|
||||
|
||||
这m次被选择,每次得到用户的点击或者没点击,把这个反馈信息记录为一个m x 1的向量,叫做C。所以这个候选臂对应的参数就是d x 1的向量,d就是特征维度数,记录为一个戴帽子的西塔,$\hat{\theta}$。
|
||||
|
||||
按照LinUCB认为,参数和特征之间线性相乘就应该得到收益:
|
||||
|
||||
$$D_{m \times d} \times \hat{\theta_{d \times 1}} = C_{m \times 1}$$<br />
|
||||
你看D也知道,C也知道,要求 $\theta$ ,这就很简单了。
|
||||
|
||||
$$ \hat{\theta}_{d \times 1} = (D_{m \times d}^{T})^{-1} C_{m \times 1}$$
|
||||
|
||||
但是由于数据稀疏,实际上求参数西塔时不会这样简单粗暴,而是采用岭回归的方法,给原始特征矩阵加上一个单位对角矩阵后再参与计算:
|
||||
|
||||
$$ \hat{\theta}_{d \times 1} = (D_{m \times d}^{T}D_{m \times d} + I_{d \times d})^{-1}D_{m \times d}^{T}C_{m \times 1}$$
|
||||
|
||||
每一个候选臂都像这样去更新它的参数,同时,得到参数后,在真正做选择时,用面对上下文的特征和候选臂的参数一起。
|
||||
|
||||
除了估算期望收益,还要计算置信区间的上边界,如果x是上下文特征,则期望收益和置信上边界的计算方法分别是下面的样子。
|
||||
|
||||
期望收益:
|
||||
|
||||
$$\hat{r} = x^{T}_{d \times 1}\hat{\theta}_ {d \times1 }$$
|
||||
|
||||
置信区间上边界:
|
||||
|
||||
$$\hat{b} = \alpha \sqrt{x^{T}_{d \times 1}(D_{m \times d}^{T}D_{m \times d} + I_{d \times d})^{-1}x_{d \times 1}}$$
|
||||
|
||||
这两个计算结果都是标量数值。置信区间计算公式虽然看起来复杂,实际上反应的思想也很直观,随着被选择次数的增加,也就是m增加,这个置信上边界是越来越小的。
|
||||
|
||||
每一次选择时给每一个候选臂都计算这两个值,相加之后选择最大那个候选臂输出,就是LinUCB了。
|
||||
|
||||
刚才说到了岭回归(ridge regression),这里多说一句,岭回归主要用于当样本数小于特征数时,对回归参数进行修正。对于加了特征的Bandit问题,正好符合这个特点:试验次数(样本)少于特征数。
|
||||
|
||||
信息量有点大,我在这里再一次列出LinUCB的重点。
|
||||
|
||||
1. LinUCB不再是上下文无关地,像盲人摸象一样从候选臂中去选择了,而是要考虑上下文因素,比如是用户特征、物品特征和场景特征一起考虑。
|
||||
1. 每一个候选臂针对这些特征各自维护一个参数向量,各自更新,互不干扰。
|
||||
1. 每次选择时用各自的参数去计算期望收益和置信区间,然后按照置信区间上边界最大的输出结果。
|
||||
1. 观察用户的反馈,简单说就是“是否点击”,将观察的结果返回,结合对应的特征,按照刚才给出的公式,去重新计算这个候选臂的参数。
|
||||
|
||||
当LinUCB的特征向量始终取1,每个候选臂的参数是收益均值的时候,LinUCB就是UCB。
|
||||
|
||||
说完简单版的LinUCB,再看看高级版的LinUCB。与简单版的相比,就是认为有一部分特征对应的参数是在所有候选臂之间共享的,所谓共享,也就是无论是哪个候选臂被选中,都会去更新这部分参数。
|
||||
|
||||
## 构建特征
|
||||
|
||||
LinUCB算法有一个很重要的步骤,就是给用户和物品构建特征,也就是刻画上下文。
|
||||
|
||||
在“Yahoo!”的应用中,物品是文章。它对特征做了一些工程化的处理,这里稍微讲一下,可供实际应用时参考借鉴。
|
||||
|
||||
首先,原始用户特征有下面几个。
|
||||
|
||||
1. 人口统计学:性别特征(2类),年龄特征(离散成10个区间)。
|
||||
1. 地域信息:遍布全球的大都市,美国各个州。
|
||||
1. 行为类别:代表用户历史行为的1000个类别取值。
|
||||
|
||||
其次,原始文章特征有:
|
||||
|
||||
1. URL类别:根据文章来源分成了几十个类别。
|
||||
1. 编辑打标签:编辑人工给内容从几十个话题标签中挑选出来的。
|
||||
|
||||
原始特征向量先经过归一化,变成单位向量。
|
||||
|
||||
再对原始用户特征做第一次降维,降维的方法就是利用用户特征和物品特征以及用户的点击行为去拟合一个矩阵W。
|
||||
|
||||
$$\phi_{u}^{T}W\phi_{a}^{T}$$
|
||||
|
||||
就用逻辑回归拟合用户对文章的点击历史,得到的W直觉上理解就是:能够把用户特征映射到物品特征上,相当于对用户特征降维了,映射方法是下面这样。
|
||||
|
||||
$$\psi_{u}=\phi_{u}^{T}W$$
|
||||
|
||||
这一步可以将原始的1000多维用户特征投射到文章的80多维的特征空间。
|
||||
|
||||
然后,用投射后的80多维特征对用户聚类,得到5个类,文章页同样聚类成5个类,再加上常数1,用户和文章各自被表示成6维向量。
|
||||
|
||||
接下来就应用前面的LinUCB算法就是了,特征工程依然还是很有效的。
|
||||
|
||||
## 总结
|
||||
|
||||
今天我和你分享了一种上下文有关的Bandit算法,叫做LinUCB,它有这么几个优点:
|
||||
|
||||
1. 由于加入了特征,所以收敛比UCB更快,也就是比UCB更快见效;
|
||||
1. 各个候选臂之间参数是独立的,可以互相不影响地更新参数;
|
||||
1. 由于参与计算的是特征,所以可以处理动态的推荐候选池,编辑可以增删文章;
|
||||
|
||||
当然,LinUCB以及所有的Bandit算法都有个缺点:同时处理的候选臂数量不能太多,不超过几百个最佳。因为每一次要计算每一个候选臂的期望收益和置信区间,一旦候选太多,计算代价将不可接受。
|
||||
|
||||
LinUCB只是一个推荐框架,可以将这个框架应用在很多地方,比如投放广告,为用户选择兴趣标签,你还可以发挥聪明才智,看看它还能用来解决什么问题,欢迎留言一起交流。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/87/b0/873b086966136189db14874181823fb0.jpg" alt="" />
|
||||
134
极客时间专栏/推荐系统三十六式/原理篇 · MAB问题/18 | 如何将Bandit算法与协同过滤结合使用.md
Normal file
134
极客时间专栏/推荐系统三十六式/原理篇 · MAB问题/18 | 如何将Bandit算法与协同过滤结合使用.md
Normal file
@@ -0,0 +1,134 @@
|
||||
<audio id="audio" title="18 | 如何将Bandit算法与协同过滤结合使用" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/a4/9a/a41a4d68b12d545f4bacb7ddc8c3709a.mp3"></audio>
|
||||
|
||||
推荐系统中最经典的算法是什么?对,是协同过滤,你已经学会抢答了。
|
||||
|
||||
是的,协同过滤是推荐系统发展史上浓墨重彩的一笔,其背后的思想简单深刻,在万物互联的今天,协同过滤的威力更加强大。与其说协同过滤是一门技术,不如说是一种方法论,不是机器在为你推荐,而是“集体智慧”在为你推荐。
|
||||
|
||||
协同过滤生动地诠释了什么是“物以类聚,人以群分”,你的圈子决定了你能见到的物品,这一点在前面的专栏中已经详细讲过了。但是这背后隐藏了一个重要的问题:是不是会存在信息茧房的问题?
|
||||
|
||||
## 信息茧房
|
||||
|
||||
其实作为一名对推荐系统略懂一二的普通海淀群众,我个人就会时常担心,是不是还能看到新的东西,是不是有惊喜。时不时乱点一通,是不是叉掉所有的推荐,让物品的推荐系统崩溃一下,这一切就是为了避免进入信息茧房,在眼前的圈子里苟且。
|
||||
|
||||
那么作为推荐系统的开发者,是不是应该做点什么呢?是的,在技术上,Bandit算法就是一个权衡探索和利用的好方法。如果把它结合传统的协同过滤来做推荐,那么在一定程度上就可以延缓信息茧房的到来,偶遇诗和远方。
|
||||
|
||||
我已经和你聊了两篇关于Bandit算法的内容,我介绍过普通的Bandit算法,也介绍过加入特征信息的LinUCB算法,今天,我要介绍的是一个新方法,如何结合协同过滤的群体智慧,与Bandit的走一步看一步一起,让两种思想碰撞,也许可以让你的推荐系统与众不同。
|
||||
|
||||
这就是2016年有人提出的COFIBA算法,下面我就开始与你聊聊这种算法。
|
||||
|
||||
## COFIBA算法
|
||||
|
||||
### 1 思想
|
||||
|
||||
很多的推荐场景中都有两个规律。
|
||||
|
||||
<li>
|
||||
相似的用户对同一个物品的反馈可能是一样的。也就是对一个聚类用户群体推荐同一个item,他们可能都会喜欢,也可能都不喜欢,同样的,同一个用户会对相似的物品反馈也会相同。这实际上就是基于用户的协同过滤基本思想。
|
||||
</li>
|
||||
<li>
|
||||
在使用推荐系统过程中,用户的决策是动态进行的,尤其是新用户。这就导致无法提前为用户准备好推荐候选,只能“走一步看一步”,是一个动态的推荐过程。这是Bandit的算法基本思想。
|
||||
</li>
|
||||
|
||||
每一个推荐候选物品,都可以根据用户对其偏好的不同,将用户分成不同的群体。
|
||||
|
||||
然后下一次,由用户所在的群体集体帮他预估可能的收益及置信区间,这个集体就有了协同的效果,然后再实时观察真实反馈,回来更新用户的个人参数用于下次调整收益和置信区间,这就有了Bandit的思想在里面。
|
||||
|
||||
举个例子,如果你的父母给你安排了很多相亲对象,要不要见面去相一下?那需要提前看看每一个相亲对象的资料,每次大家都分成好几派,有说好的,有说再看看的,也有说不行的。
|
||||
|
||||
你自己也会是其中一派的一员,每次都是你所属的那一派给你集体打分,因为他们是和你“三观一致的人”“诚不欺我”;这样从一堆资料中挑出分数最高的那个人,你出去见TA,回来后把实际感觉说给大家听,同时自己心里的标准也有些调整,重新再给剩下的其它对象打分,打完分再去见,
|
||||
|
||||
如果要推荐的候选物品较多,需要对物品聚类,就不用按照每一个物品对用户聚类,而是按照每一个物品所属的类簇对用户聚类,如此一来,物品的类簇数目相对于物品数就要大大减少。
|
||||
|
||||
# 2.细节
|
||||
|
||||
基于上述的思想,COFIBA算法要点摘要如下。
|
||||
|
||||
1. 在时刻t,有一个用户来访问推荐系统,推荐系统需要从已有的候选池子中挑一个最佳的物品推荐给他,然后观察他的反馈,用观察到的反馈来更新挑选策略。
|
||||
1. 这里的每个物品都有一个特征向量,所以这里的Bandit算法是context相关的,只不过这里虽然是给每个用户维护一套参数,但实际上是由用户所在的聚类类簇一起决定结果的。
|
||||
1. 这里依然是用岭回归去拟合用户的权重向量,用于预测用户对每个物品的可能反馈(payoff),这一点和我们上一次介绍的LinUCB算法是一样的。
|
||||
|
||||
对比上一次介绍的LinUCB算法,COFIBA的不同有两个:
|
||||
|
||||
1. 基于用户聚类挑选最佳的物品,即相似用户集体动态决策;
|
||||
1. 基于用户的反馈情况调整用户和物品的聚类结果。
|
||||
|
||||
整体算法过程如下。
|
||||
|
||||
在针对某个用户i,在每一次推荐时做以下事情。
|
||||
|
||||
1. 首先计算用户i的Bandit参数W,做法和LinUCB算法相同,但是这个参数并不直接参与到选择决策中,注意这和LinUCB不同,只是用来更新用户聚类。
|
||||
1. 遍历候选物品,每一个物品已经表示成一个向量x了。
|
||||
1. 每一个物品都对应一个物品聚类类簇,每一个物品类簇对应一个全量用户聚类结果,所以遍历到每一个物品时,就可以判断出当前用户在当前物品面前,自己属于哪个用户聚类类簇,然后把对应类簇中每个用户的M矩阵(对应LinUCB里面的A矩阵),b向量(表示收益向量,对应LinUCB里面的b向量)加起来,从而针对这个类簇求解一个岭回归参数(类似LinUCB里面单独针对每个用户所做),同时计算其收益预测值和置信区间上边界。
|
||||
1. 每个待推荐的物品都得到一个预测值及置信区间上界,挑出那个上边界最大的物品作为推荐结果。
|
||||
1. 观察用户的真实反馈,然后更新用户自己的M矩阵和b向量,只更新每个用户,对应类簇里其他的不更新。
|
||||
|
||||
以上是COFIBA算法的一次决策过程。在收到用户真实反馈之后,还有两个计算过程:
|
||||
|
||||
1. 更新user聚类;
|
||||
1. 更新item聚类。
|
||||
|
||||
如何更新user和item的聚类呢?我在这里给出了一个示意图。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/12/ed/12d5ab9b1c0ce6455ae475d0d8d923ed.jpeg" alt="" />
|
||||
|
||||
解释一下这个图。
|
||||
|
||||
(a) 示意图中有6个用户,8个物品,初始化时,用户和物品的类簇个数都是1。
|
||||
|
||||
(b)在某一轮推荐时,推荐系统面对的用户是4。推荐过程就是遍历1~8每个物品,然后在面对每个物品时,用户4在哪个类簇中,把对应类簇中的用户聚合起来为这个物品集体预测收益值置信上边界。这里假设最终物品5胜出,被推荐出去了。
|
||||
|
||||
在时刻t,物品一共有3个聚类类簇,需要更新的用户聚类是物品5对应的用户4所在类簇。
|
||||
|
||||
更新方式:看看该类簇里面除了用户4之外的用户,对物品5的预期收益是不是和用户4相近,如果是,则保持原来的连接边,否则删除原来的连接边。删除边之后相当于就重新构建了聚类结果。
|
||||
|
||||
这里假设新的聚类结果由原来用户4所在的类簇分裂成了两个类簇:4和5成一类,6单独自成一类。
|
||||
|
||||
(c)更新完用户类簇后,被推荐出去的物品5,它对应的类簇也要更新。
|
||||
|
||||
更新方式是:对于每一个和物品5还存在连接边的物品,假如叫做物品j,都有一个对这个物品j有相近收益预估值的近邻用户集合,然后看看近邻用户集合是不是和刚刚更新后的用户4所在的类簇相同。
|
||||
|
||||
是的话,保留物品5和物品j之间的连接边,否则删除。这里示意图中是物品3和物品5之间的连接边被删除。
|
||||
|
||||
物品3变成了孤家寡人一个,不再和任何物品有链接,独立后就给他初始化了一个全新的用户聚类结果:所有用户是一个类簇。
|
||||
|
||||
简单来说就是这样:
|
||||
|
||||
1. 用协同过滤来少选可以参与决策的用户代表,用LinUCB算法来实际执行选择;
|
||||
1. 根据用户的反馈,调整基于用户和基于物品的聚类结果,即对物品和用户的群体代表做换届选举;
|
||||
1. 基于物品的聚类如果变化,又进一步改变了用户的聚类结果;
|
||||
1. 不断根据用户实时动态的反馈来调整用户决策参数,从而重新划分聚类结果矩阵。
|
||||
|
||||
COFIBA算法也很容易实现,GitHub上就有。原始论文也从理论和实验两方面都证明了它的有效性。
|
||||
|
||||
## 再谈EE问题
|
||||
|
||||
整个专栏的Bandit算法系列,主要是解决推荐系统中的冷启动和EE问题。探索和利用这一对矛盾一直客观存在,而Bandit算法是公认的一种比较好的解决EE问题的方案。
|
||||
|
||||
除了Bandit算法之外,还有一些其他的探索兴趣的办法,比如在推荐时,随机地去掉一些用户历史行为(特征)。
|
||||
|
||||
解决兴趣探索,势必要冒险,势必要面对用户的未知,而这显然就是可能会伤害当前用户价值的:明知道用户肯定喜欢A,你还偏偏以某个小概率给推荐非A。
|
||||
|
||||
实际上,很少有公司会采用这些理性的办法做探索,反而更愿意用一些盲目主观的方式。究其原因,可能是因为:
|
||||
|
||||
1. 互联网产品生命周期短,而探索又是为了提升长期利益的,所以没有动力做;
|
||||
1. 用户使用互联网产品时间越来越碎片化,探索的时间长,难以体现出探索的价值;
|
||||
1. 同质化互联网产品多,用户选择多,稍有不慎,用户用脚投票,分分钟弃你于不顾;
|
||||
1. 已经成规模的平台,红利杠杠的,其实是没有动力做探索的。
|
||||
|
||||
基于这些,我们如果想在自己的推荐系统中引入探索机制,需要注意以下几点:
|
||||
|
||||
1. 用于探索兴趣的物品,要保证其本身质量,纵使用户不感兴趣,也不至于引起其反感,损失平台品牌价值;
|
||||
1. 探索兴趣的地方需要产品精心设计,让用户有耐心陪你玩儿;
|
||||
1. 深度思考,这样才不会做出脑残的产品,产品不会早早夭折,才有可能让探索机制有用武之地。
|
||||
|
||||
## 总结
|
||||
|
||||
今天,我介绍完成了MAB问题和推荐系统之间的千丝万缕联系。Bandit算法是一种不太常用在推荐系统的算法,究其原因,是它能同时处理的物品数量不能太多。
|
||||
|
||||
但是,在冷启动和处理EE问题时,Bandit算法简单好用,值得一试。当然,这个专栏介绍的所有推荐算法都不是单打独斗最好,而是与其他算法结合使用才能相映生辉,Bandit算法亦是如此。
|
||||
|
||||
今天介绍的COFIOBA算法,原理很简单,就是把协同过滤思想引入到了Bandit算法中,不再是用户独立决策,而是用户所在的群体共同决策推荐结果。
|
||||
|
||||
这样比较问题,也可以加速收敛。不知道对你有没有启发呢?欢迎留言一起讨论。感谢你的收听,我们下次再见。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/11/4c/112709b33b1bfe5539eb3f1aa124f54c.jpg" alt="" />
|
||||
Reference in New Issue
Block a user