本篇文章主要介绍一下雅虎在2012年发表的论文 【A Contextual-Bandit Approach to Personalized News Article Recommendation】,同时由于最近在做用户留存方面的工作,也涉及了一些冷启动方面的东西,尝试了很多种方法:包括性别热门、用户群体热门、bandit算法和LDA等尝试,有的效果好,有的效果差(当然和具体的业务场景和使用方法都有关系,不能否则算法或者思路本身的好坏)。最近也在尝试LinUCB算法,因此重新翻看了该论文,整理成下文,同时涉及一些个人的想法和一些实践思路。
概述
个性化Web服务通过利用用户和内容的信息调整他们的服务以满足用户的个性化需求,尽管之前的研究取得了一些进展,但仍然存在两个问题:
- Web服务具有动态更改内容池的功能,从而使传统的协同过滤算法无法使用。
- 大多数具有实际意义的Web服务要求具有快速学习和进行计算
论文中把文章推荐看作是多臂老虎机问题,一种有效的做法是根据用户和文章的上下文信息,选择文章推荐给用户,同时基于用户对文章的点击行为动态调整策略,追求点击次数最大化。实验证明加入上下文信息的Bandit算法比传统的Bandit算法CTR提升在12.5%以上,如果是基于稀疏的数据,效果会变得更好。
通常用户和物品都有其特征进行表示,在这种情况下不同用户对于同一物品而言,看法也会不同,因此识别不同内容之间的共性,并在内容池中转移该知识变得格外重要。
论文分析了已有的Bandit算法,包括UCB、E-Greedy、Thompson Smapling、朴素Bandit,然后提出了LinUCB算法,LinUCB分为两种:
- 简单的线性不相交模型 disjoint LinUCB
- 混合相交的线性模型 hybrid LinUCB
Disjoint LinUCB
之所以称为DisJoint LinUCB是因为不同臂之间的参数不共享。
首先定义每个臂的期望收益为:
其中:
- 表示臂a的参数
- 表示臂a的特征
通常模型优化采用的是最小化损失函数,在这里损失函数可以表示为:
基于岭回归得到的参数估计值为:
其中:
- 表示是一个m*d的矩阵(即m行,d列),m即选择臂a得到的m个上下文特征组,d为特征的维度
- 表示d*d的单位矩阵
- 表示臂a返回的事物是否被点击的记录向量,长度为m
根据最小平方和强化学习理论:
其中 是一个常数,为:
基于这个不等式可以选择收益最大的臂,在进行第t次实验时:
其中
其对应的算法流程为:
Hybrid LinUCB
Hybrid LinUCB考虑了臂之间的共性,因此每个臂的期望修改为:
其中:
- 表示的是用户/文章的组合特征
- 表示的是所有臂的共享未知参数
- 表示的是臂a的私有参数
由于篇幅有限,论文中并没有给出hybrid的推断,给出的伪代码如下:
评估算法
与传统的监督学习算法评测相比,融合上下文的Bandit算法的评估十分困难,由于算法的交互性,似乎只能在线上进行效果评测。然而在具体的实践过程中,这种方法是不可行的,对线上效果带来的挑战也很大。
文中提到了一种方法是根据记录的数据模拟臂的选择过程,但随即又说明了这种方法在实验过程中会引入偏差,导致结果不可信。
文中提出了一种实验方法,其实验算法如下:
- 为选择的策略,这里即为带上下文的bandit算法
- 即为时刻的历史行为记录
- 即为最终的实验指标
实验说明
实验位置
实验使用的数据是Yahoo-Today Moudle,在选择数据时,为了避免曝光位置带来的偏差,只关注Story和F1位置。
数据选择
在选取数据时,文中提出了一点:选取了一周的数据作为评估数据,运行bandit算法。从实践经验上讲这是靠谱的,避免了数据本身带来的偏差。
特征选择
- 用户维度
- 人口统计学信息(性别化为两类,年龄划分为10个等级)
- 地理特征(文中选取的是200个城市地区)
- 行为类别信息(用户的消费历史和属性信息)
- 文章维度:
- 文章URL类别(推断出数十个类别信息)
- 人工编辑的类别信息
特征降维
这里通过K-means对用户特征进行聚类,划分为5个簇,即最终得到的用户特征维度为5,最后补一列特征值为1(即第六列特征值为1,为什么为1,文中并没有说明,这里小编也不太明白,如果你有想法的话欢迎留言)
实验结论
吧啦吧啦就是比别的算法好!
注意点
- 【实践】在使用Thompson sampling时每个臂的a、b值初始化时要注意,如果差值过大,就会导致经过几次负反馈之后,排在top的臂依旧排在top,因此设计a、b值的时候需要进行特别的设计
- 计算每个臂时的特征为臂a的特征,切勿和臂下的样本特征搞混(如果一个样本是一个臂的话,那么这里的特征就是样本的特征)
- disjoint linucb中的表示的是臂a的特征,表示的是用户/文章的组合特征(臂和文章在某种程度上是一样的概念,比如候选池有100篇文章,那么每篇文章就可以看作是一个臂)
- 读论文时有些论文的实验并不太好做,这时候不仅要学习论文中算法的思路,还要学习论文中实验的设计技巧和评判技巧
LinUCB 的重点
- LinUCB 不再是上下文无关地,像盲人摸象一样从候选臂中去选择了,而是要考虑上下文因素,比如是用户特征、物品特征和场景特征一起考虑。
- 每一个候选臂针对这些特征各自维护一个参数向量,各自更新,互不干扰。
- 每次选择时用各自的参数去计算期望收益和置信区间,然后按照置信区间上边界最大的输出结果。
- 观察用户的反馈,简单说就是“是否点击”,将观察的结果返回,结合对应的特征,按照刚才给出的公式,去重新计算这个候选臂的参数。
- 当 LinUCB 的特征向量始终取 1,每个候选臂的参数是收益均值的时候,LinUCB 就是 UCB。
2019-12-27 补充
- 当备选池不大的时候,每个备选物品可以作为一个臂,如果备选池大的话可以对备选池的物品进行归类,一个类别作为一个臂
- 不同业务场景下,设置的奖励和惩罚应该是不一样的,比如点击,可以设置为1,购买设置为2,惩罚可以设置为0
- alpha的值通常是拍脑门子定的几个,通过测试比较效果,一般初始值选0.5更加稳妥些
场景应用
当来一个新用户的时候,我们并不知道该用户的偏好和兴趣,那么最常见的方法就是试探法,假设我们有10个标签,每个标签下都有运营配置的一些精品文章或者商品或者新闻等。
那么这里就可以把每个标签看作是一个臂,我们可以每个臂下展示一个事物,来对用户的兴趣进行试探,然后根据用户的行为进行结果修正。
在选取特征时,论文中使用了用户维度和臂维度的特征,那么在我们实践过程中通常可以使用下面的三大维度的特征:
- 用户维度:性别、年龄、城市、手机品牌等
- 臂维度:曝光点击率、标签类别信息等
- 用户x事物交互维度:用户在该臂下的一些交互维度特征,比如点击、曝光点击率等
在实际的应用过程中,并没有那么简单,常见的痛点如下:
- LinUCB不是一个传统的ctr算法,如何与线上服务进行集成?
- 经过onehot或者分桶之后的特征维度会增高,高维的特征必然会引起延迟增大,如何进行线上降维?
- 特征包括了用户访问时携带的特征、臂的离线和实时特征,如何进行特征拼接,进行计算?
- LinUCB和Thomson sampling、UCB相比,参数增多数倍,线上如何进行参数维护和更新?
- 新用户数量往往并不多,在有限的新用户下进行不同留存策略的ABTest,如何保证结果的可靠和有效?
- LinUCB是针对新用户的,那么对于新老用户之间的界定也十分重要,如何界定新老用户或者具体场景下的新老用户?
具体的场景、业务面对的问题和解决的办法往往是不尽相同的,如果大家决定要应用LinUCB算法,那么在使用之前一定要考虑后相关的问题和解决办法,这样才能避免使用过程中遇到的坑。
针对上边的问题并没有唯一具体的解决办法,感兴趣的欢迎在进行留言讨论。