编辑导语:推荐系统通过对用户行为喜好的预测进行信息过滤,进而为用户浏览进行推荐行为。一方面,推荐系统可以提升用户的信息阅读体验,另一方面,产品和平台也有助于借此留存用户、提高用户转化率。本篇文章里,作者对推荐系统中的召回和排序做了详细介绍,让我们来看一下。
2021年,距互联网曾经的百团大战已有近十年之久,随着时间的不断推进,技术发展也是日新月异。
从电商角度看,传统的“人找货”变成了“货找人”;从内容角度看,由信息的主动获取,到从海量信息中被动接收和挖掘有效信息。而这些都依赖于推荐系统。
对于用户而言,它作为一种“信息过滤的手段”,能够在当前信息过载的场景下,最大限度地提升用户的使用效率,建立用户对产品的信任和深度链接。
对于产品和公司而言,能够极大地提升用户活跃度与留存,提高用户转化率,这将为产品带来巨大的商业价值。
记得最早将推荐系统应用到工业界的是Amazon(亚马逊),仅仅是03年,它将传统的协同过滤算法应用在“人货匹配”的领域,开拓了电商的一条全新道路。如今的推荐系统经过技术的不断更迭,变得更加AI化、智能化。机器学习与深度学习的发展不断为其赋能,使“推荐”成为当今产品的标配。
我们进入AI的时代,产品和技术的边界,未来将变得越来越模糊,某个层面讲,有效策略的提出也往往依赖于对于技术的理解。本篇着重对于推荐模型中的召回和排序两个模块进行阐述。
一、整体框架
首先,如果要保证整个推荐系统的推荐精准度,需要依赖大量的基础样本数据,在离线条件下,将大量的样本数据“喂”给推荐模型,推荐模型将会拟合出一套普适性的算法公式,从而当每一位用户来到产品时,都能够基于用户数据带入到算法公式中,在模型的输出层得到一个结果。
这个结果是具有置信度的,将其推荐给用户,随着用户不断对推荐系统给出的结果进行反馈,用户的特征也会变得越来越丰富,从而推荐精准度也会越来越高,促成一个良性循环。
推荐系统的大致结构如上图所示,整体流程如下。
用户来到推荐页时,根据不同用户的用户数据、物品数据、所处的上下文信息等,从海量的候选物品集合中,分别经历召回层、排序层、重排序层,拉回K个用户最有可能喜欢的物品,形成最终的推荐列表(这里的物品为泛指,可以指商品、内容等)。
二、模块构成
1. 用户数据
第一类是用户的自有属性,包括年龄、性别、住址、职业、婚恋状态、受教育程度、消费水平等。
第二类是用户的行为数据,分为隐式反馈(如浏览、点击、收藏、购买)和显示反馈(如对物品的评分、评价)两类,但其中隐式反馈要比显示反馈更有价值,可用性更强。因为前者一定程度上能够代表用户真实的心理诉求,且数据量庞大,而后者数据较为稀疏。
第三类是用户的关系数据,分为强关系(如互相关注)与弱关系(互相点赞、评论),关系数据一般也可用于召回策略。
2. 物品数据
一般代表物品的自有属性,比如商品在入库时,一定会有商品的分类、型号、标签等;内容也会有分类、标签、文章长度、关键词等。除此之外还有一些统计类数据,例如商品/内容点击率,历史点赞数等等。
3. 上下文信息
描述推荐行为产生时的场景的信息,我们最常用的一般是时间(早中晚、节假日)和地点(基于LBS),此外还有天气等等。
4. 候选物品集合
一个庞大的、集海量物品为一体的“大仓库”。以电商为例,商品集可能是几十万量级甚至是百万量级。此外,推荐系统的上限,一定程度上受制于候选集的数量。换句话说,候选集的数量决定了推荐系统的天花板。
5. 召回层
理想情况下,除去计算承受能力和计算速度的约束,那么我们可以直接略过召回层,直接对百万量级的商品进行排序,然后反馈给用户。
但这是不现实的,因此召回层的意义在于缩小对商品的计算范围,将用户感兴趣的商品从百万量级的商品中进行粗选,通过简单的模型和算法将百万量级缩小至几百甚至几十量级。这样用户才能有机会在毫秒的延迟下,得到迅速的商品反馈。
召回层的特点是:数据量大、速度响应快、模型简单、特征较少。
6. 排序层
排序层的目的是得到精确的排序结果,也是推荐系统产生效果的重点,更是深度学习等应用的核心。从召回层召回的几百个物品,进行精准排序,根据规则对每个商品赋予不同的得分,由高至低来排序。由于精确度的要求,排序层的模型一般比较复杂,所需要的特征会更多。
排序层的特点是:数据量少、排序精准、模型复杂、特征较多。
7. 重排序层
重排序层也可以称之为业务排序层,这一环连接着排序层和即将给用户展示的推荐列表。
物品在排序层排好序之后,不一定完全符合业务要求和用户体验,有时我们还需要兼顾结果的多样性、流行度、新鲜度等指标,以及结果是否符合当前产品发展阶段某些流量的倾斜策略等,实施特定的业务策略,来对当前已经排好序的物品进行再次排序。比如物品的提权、打散、隔离、强插等。
举个实际的例子,一个内容平台,假设有A、B、C三类内容,我们不想让A类型的内容连续出现3次以上,就需要加一些干扰规则,将A类内容进行打散处理,使得用户最终看到的推荐列表是符合业务上的预期的。
重排序的特点是:重业务需求、重用户体验。
三、经典的模型算法
这个部分简单谈谈几个我认为应用面非常广泛且非常核心的模型算法(后续可能会继续补充),在这里只做简要介绍,不做太多公式上的说明。
1. 基于用户的协同过滤(UserCF)
首先,UserCF基于这样一个前提假设:喜欢相似物品的用户之间,存在着相似的兴趣偏好。
以电商为例,假设电商库存中有a、b、c、d四件商品,平台上一共有A、B、C、D、E五位用户,根据用户在平台上的行为和动作,我们基本能够获取到每位用户对于a、b、c、d四件商品大致的偏好程度。
如何衡量偏好程度呢?可以采用打分的方式,根据用户对于物品的显示反馈或隐式反馈,来综合得出对于物品的打分,比如对商品点赞加1分,踩一下减1分,浏览商品加1分,收藏加2分,购买加3分(这里的打分方式只是用于说明问题,实际可能会略复杂一些),这样就可以得出每个用户对于每个物品的综合打分。
但这里一定会存在用户与某个物品尚未产生交互行为的情况,那么对应的分值就为“空”,也可以取0分或者是取纵向的平均分来代替空值。
最后得到如下图的矩阵形式,这样的矩阵也称之为“共现矩阵”。
说回到UserCF,如果我们想预测用户E对于物品c的偏好,那么基于UserCF的思想,就需要找到与用户E最相似的用户,因为前面已经做出了假设,与用户E最相似的用户对于物品c的评分最有可能是用户E对于物品c的真实打分,其置信度是最高的。
那么可以通过用户向量间余弦相似度的方式来寻找最相似的k个用户,夹角越小,两个用户就越相似。
sim(i,j)=cos(i,j)
得到相似度之后,相似度就可以作为置信权重来综合对k个相似用户的打分,得到最终预测打分。
UserCF的应用场景和优缺点:
- 因为UserCF是基于用户相似度的推荐,所以它具备了非常强的社交属性,容易通过社交关系来传播符合用户口味的东西,因此它更适用于新闻推荐这样的场景,一方面新闻内容具有实时性、热点性,而UserCF更擅长于捕捉这一类的内容。另一方面,新闻内容的数量要远远多余用户数量,因此计算向量相似度时,要比ItemCF的时间复杂度更低。
- 新用户往往历史行为数据非常稀疏,可能会得到【0,0,0,0,0,…..,1】这样的向量,导致根据用户相似度推荐的物品准确度和置信度会非常低。也就是说如果遇到低频应用以及用户冷启动会比较麻烦,不太适用。
- 还有一种情况是,用户数远远多于商品数,用户数的不断增长会导致用户相似度矩阵难以维护,它用到的存储空间的增长速度是呈指数级的。
2. 基于物品的协同过滤(ItemCF)
首先,ItemCF基于这样一个前提假设:用户对于不同物品间的偏好相似,那么物品间也是相似的。
它的原理与UserCF类似,还是上面那张图,可以看作是UserCF的另一面。ItemCF采用纵向的向量,作为物品的表示向量,可以通过物品向量间余弦相似度的方式来寻找最相似的k个物品,夹角越小,两个物品就越相似。
得到相似度之后,相似度就可以作为置信权重来综合k个相似物品的打分,得到最终预测打分。
ItemCF的应用场景和优缺点:
- 因为UserCF有一些明显的缺点,所以Amazon和Netflix最早应用的都是ItemCF,它相比用户向量,物品的向量变化要更为稳定,因此广泛用于电商和视频推荐的领域,当用户对某一类商品或某一类电影产生兴趣时,此时给Ta推荐同类型的商品或电影是一个可靠的选择。
- ItemCF不具备很强的泛化能力。当一个热门商品出现后,它容易和大量的商品都具有相似性,导致推荐商品时,热门商品的出现概率会非常高,形成了“头部效应”,同样也致使处于长尾的商品较难被挖掘,因为长尾商品的特征向量会非常稀疏。所以要想解决这个问题,需要后期添加一些干预策略在里面。
3. 矩阵分解(隐向量的表达)
矩阵分解算法是基于协同过滤进化而成的,它可以认为是一种以数学的方式来优化了协同过滤算法。
前面提到,协同过滤的计算核心是生成了“共现矩阵”,那么我们可以将这个共现矩阵继续拆分,形成一个用户矩阵和一个物品矩阵,也就是得到了用户的隐向量和物品的隐向量,这样就能够用隐向量的距离来选取用户感兴趣的物品了。它的思想和embedding(下文会提到)非常相似,泛化能力极强。
共现矩阵中的每一个小单元中对应的评分,约等于,对应用户矩阵中行向量与物品矩阵中列向量每个位置对应元素的乘积之和。
如上图所示,共现矩阵是n×n维的,用户矩阵是n×k维的(图中k=2),物品矩阵是k×n维的。其中k值根据具体工程而定。其中k值越小,模型泛化能力越强。k值越大,模型泛化能力越差,但表达能力越强。
至于如何得到这样的用户矩阵和物品矩阵,采用的是机器学习中的梯度下降法,并且最小化损失函数,得到的最优近似解。具体不展开论述了。
4. 逻辑回归(LR)
说到逻辑回归算法,它实在是太经典了,而且应用非常非常广泛,甚至可以说是深度学习神经网络的基础。在深度学习模型中,一般常作为神经网络的输出层。先看一下逻辑回归的图像:
可以看出,逻辑回归可以将所有的输入全部映射到0到1之间,因为0和1的存在,逻辑回归可以广泛应有于二分类问题。
在工业界,我们应用逻辑回归模型,通常是将【0~1】这个值域转化为对概率的预测,因为概率就是从0到1的。一个二分类问题就可以等价于,对于一个样本是否是正样本的概率(可以是点击率CTR)进行预测,最后根据预测的概率值,从上至下来对推荐列表排序(有时在极限情况下,我们甚至可以认为,当输入只要大于0时,输出就为1;当输入只要小于0时,输出就为0,从而简化模型)。
1)逻辑回归的优势
与传统的协同过滤不同,协同过滤仅利用了用户对物品的偏好特征,忽略了用户特征、物品特征,以及场景特征。协同过滤会丢失掉大量的尚未利用的有效信息,导致给出的结果并不是最权威的。
逻辑回归能够很好避免这一点,它能够将用户、物品、上下文、历史行为特征全部融入进模型中,并分别为每一组特征拟合出每一组权重,最后得到的结果更具有可信度。
2)逻辑回归的推荐流程
- 获取大量的样本数据。将用户属性、物品属性、时间、地点等特征全部转换为数值型特征向量。
- 以点击率CTR为优化目标,将所有的特征向量输入进模型中,经过一段时间的训练,为每一组特征拟合出一个权重参数。
- 模型上线时,每个用户实时的数据特征,经过模型处理后,为物品得到用户可能点击的概率,根据概率由上至下排序,将反馈出一个推荐列表。
有些同学看到这可能会有疑问了,像用户年龄、商品价格、文章点赞数这些,都可以很方便地转换为数值型特征向量,可是像用户ID、用户性别、时间、地点呢?本身不是数值类型的属性,是如何转换的呢?
这其实涉及到one-hot编码,以及multi-hot编码。举个例子,对于结构化的数据(比如性别、星期几)都可以用向量的方式来表示,比如[1,0,0]可以代表一个男性,[0,1,0]可以代表一个女性,[0,0,1]可以代表性别未知;星期几也是同理,一周有七天,就有七个维度,[1,0,0,0,0,0,0]就可以代表星期一,依此类推。
四、召回策略
1. 多路召回策略
在召回层这个阶段,我们一方面希望能够召回尽量多的物品,提升召回物品的丰富度。也就是说,我们希望召回的这些物品的覆盖面尽可能全,这里有一个计算指标,叫做召回率。
另一方面,如果召回了特别多的物品,虽然满足我们对召回覆盖面的预期,但随着物品数量增多,又会极大地影响计算机的计算速度。
在两方面的权衡之下,我们通常采用一种方法叫做多路召回策略。但召回策略是强依赖于业务的,每个不同的产品处在不同的时期,所用到的召回策略也不尽相同。
多路召回策略简单地说,就是采用了多种类型的小型策略,每一种小型策略分别从候选集中召回一定数量的物品,这样我们就会得到召回物品的一个大的组合,进而将这个组合再交付到排序层进行排序。
多路召回的好处在于:
- 它依赖于小型策略的简单模型的计算,能够大幅降低响应时间;
- 多路的特点能够同时应用多种小型策略,一定程度避免的单一策略召回所导致的精确度的缺陷。
2. 基于Embedding的召回
这种召回方法偏向于技术层面,我认为策略PM可以做一个大致了解,先简单谈谈什么叫做Embedding。
Embedding可以等价类比为“向量化”或“向量映射”,是一种向量的映射方式。Embedding的作用就是将一个高维稀疏的特征向量映射(或者叫转化)为一个低维稠密的特征向量,同时保留原有高维向量的显著特征。Embedding是整个深度学习框架中不可或缺的第一个层级(其实就是用于特征转换)。例如前面提到的“矩阵分解”,就可以看作是Embedding的一个变种。
那么什么是基于Embedding的召回呢?
这里有一个前提,就是说如果用户特征与物品特征这两者被抽象出的Embedding向量是相似的(向量离得最近),那么该用户就越可能喜欢该物品,从而将该物品从候选集中召回。好了,那么问题就可以等价更该为:如何为用户Embedding去寻找最相似的物品Embedding?
最传统的计算方式是对用户和物品的Embedding进行向量内积运算,这代表着需要对每一位用户的Embedding,都要把候选集中的海量物品对应的Embedding向量都做一遍匹配计算,这意味着非常庞大的时间复杂度。
因此引申出了另一种方式去计算Embedding相似度,既然两者同属于一个向量空间,那么找到与用户Embedding向量最相似的物品Embedding向量就可以理解为是:基于用户向量去搜索与用户向量最邻近向量的过程,这种方式称之为“局部敏感哈希(Locality Sensitive Hashing, LSH)”。
局部敏感哈希的原理我就不在这里赘述了,原理略微偏数学一些,可能与产品扯得越来越远了,有兴趣的同学可以查查百度。不过基于Embedding的召回方式是非常有实践意义的,Youtube推荐系统在召回层就是利用了这个召回策略。
总的来说,它有几个好处。
- 多路召回的小型策略(比如热门排行、最近流行等)等信息都可以作为Embedding召回方法中的附加信息,带入到向量中,所以也相当于具备了多路召回的能力。
- 基于Embedding的召回可以使得物品分值更具有连续性,因为多路召回策略中,各个小型策略近似可以认为是相互独立的,所以不同召回策略下的候选集是不具备可比性的,无法决定每个小型策略放回候选集的大小。而Embedding召回可以把相似度作为唯一指标,能够随意限定召回的候选集大小。
五、排序策略
排序一直是推荐系统的核心部分,排序模块目前一般使用机器学习和深度学习的技术来提供“千人千面”的排序结果,属于典型的技术驱动的模块。如前文所提,排序模块分为两大块,一块叫做排序层(机器学习),另一块叫做重排序层(业务排序层)。
对于涉及机器学习和深度学习的排序层,它十分依赖于算法模型给出的排序结果。一般情况下通过优化模型和调参,或是输入大量有价值的样本数据,通过一段时间后的训练基本可以达到一个较为稳定的水平。机器的表现固然很好,但最终的推荐列表是给用户展示的,也会不可避免的出现各种各样的问题。
举个例子,一个视频内容平台,某一个秀身材的美女视频我点进去看了一眼,或者我不小心误触进去了,那么同样类型题材的视频就会连续不断地推给我。这不仅是算法越推越窄的问题,实际上是缺乏对新颖性和多样性的考虑,缺乏对排序的干预处理。所以在推荐系统的开发之前就需要考虑它的适应性和可调整性。
排序主要是为了解决重要性的问题。排序越靠前的内容,对于用户而言重要程度越高。对于业务和产品而言,不同时期、不同阶段对于不同用户给出的排序规则一定是不同的,下面介绍一些常用的排序策略。
1. 热度策略
热度算法一般是用来推荐比较热门的内容,近期入库且曝光点击率高的,需要用多个维度分别赋予不同的权重来召回内容。公式大致如下,受制于一些因素,不宜公开特别详细,可以简单体会一下里面大概的思路即可。
内容热度=[a*内容浏览量+b*(收藏量+分享数)-c*(举报量+被踩量)]*点击率倍数
2. 流行度降权
畅销榜单上的热门物品,其实更容易被推荐,尤其是使用ItemCF时,头部效应会变得更加明显,为了解决长尾曝光的能力,可以将热门物品适当降权,让长尾物品更有竞争力。如此,推荐系统给出的原始打分将会被再次修正。
流行度降权的一种计算方式如下所示,r(ui)是推荐系统给出的原始分值,M(i)是物品的销量,a是一个可调节的参数,它的意义在于保护销量小于a的物品不被降权。
当然除此之外还有更多其他函数可以使用,比如分段函数,我们可以根据销量在不同的范围,分别给定不同的降权系数。
3. 时间衰减
时间衰减的概念最早来源于牛顿冷却定律,物体所损失热的速率与周围环境温度差是成正比的。在内容实时性方面,针对缺乏实时性的内容,我们可以利用一个类似的时间衰减算法来给这类内容做降权处理。
如下所示,r(ui)是推荐系统给出的原始分值,t0-t代表当前时间与过去某一时刻的时间相差多久,b是控制衰减速度的参数,b越大衰减速度越慢,b越小衰减速度越快。
4. 内容打散
如何解决相同类型内容连续不断的推荐给用户的问题呢?其实最简单的做法就是直接加入业务规则来限制。
比如曝光点击率高的优先排序,此外同一类型的内容连续不得超过3个,若超过3个,就将这些内容之后第一个不属于此分类的内容,强制插入到前面的结果中去。
这种做法一般比较麻烦且效果有限。一个比较好用的内容打散算法如下所示,它能够拉大同类内容的区分度,从而使得不同的内容实现混插。其中V(k,j)代表推荐结果中,分类k中排序为j的商品的推荐分数。V(k,j)”代表最终修正后的推荐分数。u代表离散率,越接近于0,则离散性越强。
六、总结
首先很感谢你能耐心地看到这里,不过受制于篇幅所限,很多内容无法完整展开。
其实对于推荐系统而言,说复杂也复杂,说简单其实把它看透了也是很容易理解的。
当然推荐系统的知识远不止于此,作为一个产品上线时,如何进行评估推荐系统的好与坏?如何进行正确的AB测试来验证策略手段是否正确?后续应该还会持续添加相关的内容,并且下一个主题想和大家聊一聊搜索相关的玩法。严格来讲,搜索和推荐其实是不分家的,推荐可以个性化,那么搜索更是可以,因为它正是推荐的另一面。