点击上方“大数据与人工智能”,“星标或置顶公众号”
第一时间获取好内容
作者丨gongyouliu
这是作者的第15篇文章,约1.1万字,阅读需70分钟
以下为正文:
作者在《推荐系统产品与算法概述》这篇文章中简单介绍了协同过滤算法。协同过滤算法是在整个推荐系统发展史上比较出名的算法,具备举足轻重的地位,甚至在当今还在大量使用。
本篇文章作者会详细讲解协同过滤推荐算法的方方面面,这里所讲的也是作者基于多年推荐系统研究及工程实践经验的基础上总结而成,希望对大家学习协同过滤推荐算法有所帮助,提供一些借鉴。
本文会从协同过滤思想简介、协同过滤算法原理介绍、离线协同过滤算法的工程实现、近实时协同过滤算法的工程实现、协同过滤算法应用场景、协同过滤算法的优缺点、协同过滤算法落地需要关注的几个问题等7个方面来讲述。希望读者读完本文,可以很好地理解协同过滤的思路、算法原理、工程实现方案,并且具备基于本文的思路自己独立实现一个在真实业务场景中可用的协同过滤推荐系统的能力。
在正式讲解之前,先做一个简单定义。本文用”操作过“这个词来表示用户对标的物的各种操作行为,包括浏览、点击、播放、收藏、评论、点赞、转发、评分等等。
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/d7d23abf05bc6f5f3b8ff80846397b16.gif)
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/0eb7476890a5d1621cdde59995172158.gif)
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/d7d23abf05bc6f5f3b8ff80846397b16.gif)
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/0eb7476890a5d1621cdde59995172158.gif)
协同过滤的核心是怎么计算标的物之间的相似度以及用户之间的相似度。 我们可以采用非常朴素的思想来计算相似度。 我们将用户对标的物的评分(或者隐式反馈,如点击、收藏等)构建如下用户行为矩阵(见下面图2),矩阵的某个元素代表某个用户对某个标的物的评分(如果是隐式反馈,值为1),如果某个用户对某个标的物未产生行为,值为0。 其中行向量代表某个用户对所有标的物的评分向量,列向量代表所有用户对某个标的物的评分向量。 有了行向量和列向量,我们就可以计算用户与用户之间、标的物与标的物之间的相似度了。 具体来说,行向量之间的相似度就是用户之间的相似度,列向量之间的相似度就是标的物之间的相似度。 为了避免误解,这里简单解释一下隐式反馈,只要不是用户直接评分的操作行为都算隐式反馈,包括浏览、点击、播放、收藏、评论、点赞、转发等等。 有很多隐式反馈是可以间接获得评分的,后面会讲解。 如果不间接获得评分,就用0、1表示是否操作过。 在真实业务场景中用户数和标的物数一般都是很大的(用户数可能是百万、千万、亿级,标的物可能是十万、百万、千万级),而每个用户只会操作过有限个标的物,所以用户行为矩阵是稀疏矩阵。 正因为矩阵是稀疏的,会方便我们进行相似度计算及为用户做推荐。
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/de1730fede65a7984af7d35b9edcf1e0.png)
相似度的计算可以采用cosine余弦相似度算法来计算两个向量
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/301ebd6e6f612d013091c3835fadc215.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/aa1515569a2b3e86ceaa280dc5da3aa6.png)
计算完了用户(行向量)或者标的物(列向量)之间的相似度,那么下面说说怎么为用户做个性化推荐。
2.1 基于用户协同过滤
用户u对标的物s的喜好度sim(u,s)可以采用如下公式计算,其中U是与该用户最相似的用户集合(我们可以基于用户相似度找到与某用户最相似的K个用户),
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/40e6d9c9736ea390f236bc441f86af63.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/38d86ff9976424200d3a94fc7fea28c6.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/f9d53584fd99fc337f98eee931cc737e.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/38d86ff9976424200d3a94fc7fea28c6.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/b73daa3a1fc674fc6c7c1090df9c91db.png)
2.2 基于标的物的协同过滤
类似地,通过将用户操作过的标的物最相似的标的物推荐给用户,这就是基于标的物的协同过滤的核心思想。
用户u对标的物s的喜好度sim(u,s)可以采用如下公式计算,其中S是所有用户操作过的标的物的列表,
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/ac61cf318b3094f3c73c552ef9a3335e.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/595e73bb144f52a00aafbf6c21df698b.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/c0e921bfd1d6252b571d3f2f99d93135.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/595e73bb144f52a00aafbf6c21df698b.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/8663aea83035e4f8a3b2ae99668b8963.png)
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/d7d23abf05bc6f5f3b8ff80846397b16.gif)
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/0eb7476890a5d1621cdde59995172158.gif)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/9b11e35ceb16724a34b70f1521d3e53e.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/9ac32f7a5f502f28178314549814e784.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/3ff517405c2c540a945a9a3a0a489c2d.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/9b11e35ceb16724a34b70f1521d3e53e.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/dd2d896b0b14b54cbc561810a29219a7.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/9b11e35ceb16724a34b70f1521d3e53e.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/6d7b1fe66f4ed494d7f0d6dfb6a7f431.png)
有了上面的简单分析,就容易分布式计算相似度了。 下面我们就来讲解,在Spark上怎么简单地计算每个标的物的topK相似度。 在Spark上计算相似度,最主要的目标是怎么将上面巨大的计算量(前面已经提到在互联网公司,往往用户数和标的物数都是非常巨大的)通过分布式技术实现,这样就可以利用多台服务器的计算能力,解决大计算问题。 首先将所有用户操作过的标的物”收集“起来,形成一个用户行为RDD,具体的数据格式如下:
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/f62a863c1f745d9059c63a84b7f81cc2.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/f62a863c1f745d9059c63a84b7f81cc2.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/6ea2d7747cfbd5c942aea04e10bf767d.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/f39a21bf65d31caa5b07c94609207364.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/9b11e35ceb16724a34b70f1521d3e53e.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/9b11e35ceb16724a34b70f1521d3e53e.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/9f9c0a7023598581c31412ef82212135.png)
当所有用户都按照图4的方式转化为标的物对及得分(图4中右边的
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/22685d8125d9ed37aa72c29a5fa79c7b.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/00e9c37c4b03ec3ba4f9cddb8b153730.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/d9f3787c2d76a20d58c176cfc17f91f5.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/2d9ab9854eaed45278c580bbe2278426.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/664b12b27aa49963f0084fb86e06390f.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/e1b0496f2169203113434cdbd9fc9370.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/d9f3787c2d76a20d58c176cfc17f91f5.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/d9f3787c2d76a20d58c176cfc17f91f5.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/9287c6ba22ff08b882a1e6e7c91e9583.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/9b11e35ceb16724a34b70f1521d3e53e.png)
通过上面这些步骤,公式1中的分子和分母基本都很容易计算出来了,我们通过下图的代码(下面的broadcast即是
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/c4771d88aaecc8b5947b0412eecc89c9.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/9b11e35ceb16724a34b70f1521d3e53e.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/c80c79dd83e6a724e99a53c499776a9d.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/ffea1cc24d331977125653120f891543.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/9b11e35ceb16724a34b70f1521d3e53e.png)
有了上面的准备,下面我们来说明一下怎么计算每个标的物的topK最相似的标的物。 具体的计算过程可以用如下的Spark Transformation来实现。 其中第三步的TopK需要我们自己实现一个函数,求
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/f5790896c718ef76fb7c7dd7350e3ab3.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/c3c0b94f7825750d92b43aa6955ebad7.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/3559ec0742fb28b39e0c92ed013e7603.png)
到此为止,我们通过Spark提供的一些Transformation操作及一些工程实现上的技巧计算出了每个标的物topK最相似的标的物。 该计算方法可以横向拓展,所以再大的用户数和标的物数都可以轻松应对,最多可能需要多加一些服务器。
有了1中计算出的标的物topK最相似的标的物,下面我们来说明一下怎么为用户生成个性化推荐。 生成个性化推荐有两种工程实现策略,一种是看成矩阵的乘积,另外一种是根据第二节2中”基于标的物的协同过滤“中的公式来计算,这两种方法本质上是一样的,只是工程实现上不一样。 下面我们分别讲解这两种实现方案。 (1)通过矩阵相乘为用户生成推荐
上面图2中的矩阵是用户行为矩阵,第i行第j列的元素代表了用户i对标的物j的偏好/评分,我们将该矩阵记为 ,其中n是用户数,m是标的物数。图7中的矩阵是标的物之间的相似度矩阵,我们将它记为
,这是一个方阵。
和
其实都是稀疏矩阵,我们通过计算这两个矩阵的乘积(Spark上是可以直接计算两个稀疏矩阵的乘积的),最终的结果矩阵就可以方便用来为用户推荐了:
。其中的第i行
代表的是用户i对每个标的物的偏好得分,我们从这个列表中过滤掉用户操作过的标的物,然后按照得分从高到低降序排列取topN就是最终给用户的推荐。
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/57d8d5f50e1b1405b045ab39beb833cd.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/13b183421e45eeee98e0aea8cb11a09e.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/57d8d5f50e1b1405b045ab39beb833cd.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/57d8d5f50e1b1405b045ab39beb833cd.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/d4667fcf6ac430b35bbf2cfb5d407b32.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/3afa8305603e2761b48feb144105a6ed.jpeg)
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/d7d23abf05bc6f5f3b8ff80846397b16.gif)
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/0eb7476890a5d1621cdde59995172158.gif)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/783d9ca3e4da720d789253c38d013141.jpeg)
首先,用户U在时间窗口W内的所有k次行为
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/5ba3a258706965f9749be0b41d1a09b4.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/ab6c5d6f69b827af4968137480f47699.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/b22c16304532cb14e0b84b76aa8543ce.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/ad3831af9e04aed0ade8c61c33393a2b.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/4329c87e867e0cd0b46372a8c34961da.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/4329c87e867e0cd0b46372a8c34961da.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/ad3831af9e04aed0ade8c61c33393a2b.png)
这里说一下,如果用户操作的某个标的物已经在行为表UAction中(这种情况一般是用户对同一个标的物做了多次操作,昨天看了这短视频,今天刷到了又看了一遍),我们需要将这两次相同的行为合并起来,具体上我们可以将这两次行为中得分高的赋值给行为表中该标的物的得分,同时将操作时间更新为最新操作该标的物的时间。 同时将时间窗口W中该操作行为剔除掉,不参上面提到的时间窗口W中的操作行为跟UAction表中同样的操作行为的笛卡尔积计算。
4.3 更新用户的行为记录HBase表: UAction
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/86f612bebbe0a5cda93af722a4c0685c.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/c598660c63ec2f83d7d32657416ed1af.png)
其中t是用户操作过的标的物,
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/66d76db8b6f81977bd10c7c8589a12de.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/46cfc244a0360c67b6893b39d5312091.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/79cdb3bfa74bcdbe6660befa208ed56c.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/1f478c3787d3e6e1ae4932eeb70a67a5.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/9a10f94070a5733027939eba120d9213.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/3527bda7ff22bc5824eccc7b9676571c.png)
当我们计算完了用户U跟所有标的物的得分之后,通过对得分降序排列取topN就可以作为U的推荐了。 当标的物量很大(特别是新闻短视频类产品)时,实时计算还是压力非常大的,这时我们可以采用一个简单的技巧,我们事先从CR表中过滤出跟用户行为表中至少有一个标的物t有交集的标的物s(即标的物对
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/2b3bc36d51ab7edef43cbf1e37c6e0a5.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/5b8fb610fcacd2aba5a2e8c709da600d.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/86f612bebbe0a5cda93af722a4c0685c.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/46cfc244a0360c67b6893b39d5312091.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/86f612bebbe0a5cda93af722a4c0685c.png)
上面针对一个用户怎么实时计算协同过滤做了讲解,那么在一个时间窗口W中有若干个用户都有操作行为,这时可以将用户均匀分配到不同的Partition中,每个Partition为一批用户计推荐。 具体流程可以参考下面图11。 为每个用户计算好推荐后,可以插一份到HBase中作为一个副本,另外还可以通过Kafka将推荐结果同步一份到CouchBase集群中,供推荐Web服务为用户提供线上推荐服务。
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/7efab82c5902bb434910fa54a2a0ec56.png)
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/d7d23abf05bc6f5f3b8ff80846397b16.gif)
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/0eb7476890a5d1621cdde59995172158.gif)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/918e44d424a4bd31bd65e26aca13608a.jpeg)
5.2 标的物关联标的物推荐(范式)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/aad21df1ce5f957d4d002c84aa75508e.jpeg)
5.3 其他应用形式及场景
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/d7d23abf05bc6f5f3b8ff80846397b16.gif)
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/0eb7476890a5d1621cdde59995172158.gif)
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/d7d23abf05bc6f5f3b8ff80846397b16.gif)
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/0eb7476890a5d1621cdde59995172158.gif)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/00966588f1eecb84769a4825756ad3b4.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/6fa85565df90973e3b0d3e7ef702c07d.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/6fa85565df90973e3b0d3e7ef702c07d.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/0d39de904a3066d5242ef59dafc7f836.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/31aa4239ec21fb5a8eb698475285f6c3.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/3703796b9347cc653f401cd321f681cc.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/1a62bd51e28d8531be796a71d080e9e0.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/44eb60b7439007881e98203eecdd7c1b.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/0cb7c8b1a747d1fd632667f782a36326.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/fca36c79f3d75e321836cc740b65e3bc.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/d1eebd667f771c9abb0c67b1ca59ad42.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/a33ef74a974f290da22e57167c6557a4.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/1e0faf864a870c61b2c1a32de9b1f120.png)
所谓用户冷启动就是新用户没有太多的行为,我们无法为他计算个性化推荐。这时可行的推荐策略是为这类用户推荐热门标的物、通过人工编排筛选出的标的物。或者用户只有很少的行为,协同过滤效果也不好,这时可以采用基于内容的推荐算法补充。
(2) 标的物冷启动
所谓标的物冷启动就是新的标的物加入系统,没有用户操作行为,这时协同过滤算法也无法将该标的物推荐给用户。可行的解决方案有三个:
首先,这类标的物可以通过人工曝光到比较好的推荐位(如首页)上,在尽短的时间内获得足够多的用户行为,这样就可以“启动”协同过滤算法了。 这里有个比较大的问题是,如果该标的物不是主流的标的物、不够热门的话,放在好的位子不光占用资源同时对用户体验还不好。 其次,在推荐算法上做一些策略,可以将这类新的标的物以一定的概率混杂在用户的推荐列表中,让这些标的物有足够多的曝光,在曝光过程中收集用户行为,同时该方法也可以提升用户推荐的多样性。 最后,这类标的物也可以通过基于内容的推荐算法来分发出去,作者在《基于内容的推荐算法》中已经讲过内容推荐,这里不再赘述。 (3) 系统冷启动 所谓系统冷启动,就是该产品是一个新开发不久的产品,还在发展用户初期阶段,这时协同过滤算法基本无法起作用,最好采用基于内容的推荐算法或者直接利用编辑编排一些多样性的优质内容作为推荐备选推荐集。![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/d7d23abf05bc6f5f3b8ff80846397b16.gif)
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/0eb7476890a5d1621cdde59995172158.gif)
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/d7d23abf05bc6f5f3b8ff80846397b16.gif)
![640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/0eb7476890a5d1621cdde59995172158.gif)
2. item-based top-n recommendation algorithms 3. Collaborative filtering for implicit feedback datasets 4. Amazon.com reecommendations: Item-to-item collaborative filtering 5. TencentRec- Real-time Stream Recommendation in Practice 6. Google news personalization:Scalable online collaborative flitering 7. Forgetting mechanisms for incremental collaborative filtering 8. Scalable collaborative filtering using incremental update and local link prediction 9. GroupLens: An Open Architecture for Collaborative Filtering of Netnews
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/b720d8d1b59efcdbbc897e51007207f4.jpeg)