首页 > 技术文章 > 漫谈协同过滤推荐算法

timssd 原文

引言

       当今的信息时代,推荐无处不在:当你在网上浏览一件衣服的时候,它给你推荐搭配的套装;当你想要购买一本图书的时候,它给你推荐相类似的书籍;当你打开手机app想要看场电影的时候,它给你推荐一系列你可能感兴趣的…推荐算法似乎总是可以抓住你的心理,把一些你未接触过的新鲜事物恰如其分的摆到你面前,接下来就来谈谈其中很火爆的一类推荐算法。 
       协同过滤推荐,不同于基于内容的推荐,要理解好“协同”这个词,它基于海量的用户与偏好信息进行推荐。当一个人想找部电影来看,想找本书来看,当他有一个明确的目标指向并基于这个指向去寻找适合他的信息,这叫“搜索”;如果没有一个明确的方向,他可能会寻求口味相似朋友的帮助,或者他以前看过某本书某部电影现在寻找相类似的,这就是“推荐”。协同过滤推荐又分为两种:基于用户的协同过滤推荐与基于物品的协同过滤推荐。前者就是你去寻求朋友的帮助,看看他们都喜欢看什么样的电影什么样的书,里面或许有你感兴趣的;后者则是你看了一部喜欢的电影之后还想要看看有没相似的,比如某购书网站的某和你兴趣相似的用户也喜欢某某书。

基于用户的协同过滤推荐

       物以类聚,人以群分,能走到一起的朋友或多或少都会有兴趣相投的部分,基于用户的协同过滤正是利用这点原理:既然我们有着相似的兴趣爱好,那么我喜欢的多半你也会喜欢,那么就不妨推荐给你。明确了这点,接下来就是确定那个和你兴趣相投的人了。如何定义这个兴趣相投呢?很简单的道理,让一个成天看科幻片的人去推荐一部爱情电影想想就是不靠谱的,至少要爱好相一致或者相类似嘛。如果把所有的物品罗列出来,然后让甲和乙分别对这些物品根据他们的喜好打个分,有了这个打分,那么就可以用一个“相似度”的玩意来判断他们是否兴趣相投了。有了相似度以后,就可以在茫茫人海中寻找那个和你三观最一致的人了,然后从他的喜好列表中挨个给你推荐,相信总有一款会合你心水。

基于物品的协同过滤推荐

       前面介绍了通过朋友推荐的情况,可是万一这个人兴趣比较古怪以致于找不到品味相似的人怎么办?这个世界上的人太多,找这个兴致一样的人花了太多时间怎么办?所幸还有另外的推荐算法,如果一个人买了腮红买了口红买了眉笔,那么她多半是个爱美的妹子,这时候你给她推荐一款香水她多半会乐于接受,它是基于这样的原理:一个人喜欢某些东西,那么对于和他的喜好相近的一些事物也有可能喜欢。在这里同样有一个相似度的概念,以化妆品举例,往往妹子们在买一样化妆品比如腮红的时候会和另外一样东西比如口红一起买,那么这两样物品相关性就是比较大的,这样根据历史的数据就可以确定物品间的相似度。有了这个相似度,同样就可以根据你购买过的东西推荐一些相关的商品了。 
       以上就是协同过滤算法的主要思想,在下一篇文章中将阐述算法中的具体问题。

在上一篇文章中介绍了协同过滤算法的基本原理,在这一篇文章中将对算法中的具体细节展开详述。无论是基于用户的协同过滤算法还是基于物品的协同过滤算法,都涉及到一个相似度的计算,那么这个相似度如何定义呢?下面就来介绍几种主流的相似度定义。

相似度

欧氏距离

      假设有数据点a⃗ =(a1,a2,,an)b⃗ =(b1,b2,,bn),那么a⃗ b⃗ 之间的欧氏距离则为

(a1b1)2+(a2b2)2++(anbn)2−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−√

余弦相似度

      假设有向量a⃗ b⃗ ,那么在向量空间中它们会有一个夹角,可以根据夹角的大小来判断这两个向量的接近程度。而我们知道a⃗ b⃗ =a⃗ b⃗ cosa⃗ ,b⃗ ,自然而然的就可以利用夹角的余弦值来定义相似度

cosa⃗ ,b⃗ =a⃗ b⃗ a⃗ b⃗ =a1b1+a2b2++anbna21+a22++a2n−−−−−−−−−−−−−−√b21+b22++b2n−−−−−−−−−−−−−√

皮尔逊相关系数

      皮尔逊相关系数度量的是两个向量的线性相关性,取值范围为[-1,1],当相关系数为1时两个向量完全正相关,当相关系数为-1时两个向量完全负相关。其计算公式为

ρX,Y=cov(X,Y)σXσY=E((XμX)(YμY)σXσY=E(XY)E(X)E(Y)E(X2)E2(X)−−−−−−−−−−−−−√E(Y2)E2(Y)−−−−−−−−−−−−−√

没错,它就是线性代数里面的相关系数,由变量的协方差与标准差之商给出。 
       有了相似度的定义,我们来看在协同过滤算法里面是怎么使用的,涉及到哪些数据。对于基于用户的协同过滤算法,我们的目标是寻找相似的用户,那么就要计算用户之间的相似度,因此要对每一个用户都建立其相关的特征。典型的一些特征包括用户的基本信息,诸如性别、年龄、职业等等;别忘记我们的推荐是基于喜好来进行商品推荐,所以用户关于商品的偏好程度尤其重要,譬如对于一个电商网站,用户在某个商品页面的停留时间,浏览次数等等行为都在某种程度上反映了关注程度都可以作为一个特征。将用户的这一系列特征串起来组成一个向量,便可以计算两两之间的相似度了。 
      对于基于物品的协同过滤也是同理,通过构建物品的一系列特征从而计算物品之间的相似度。计算物品之间的相似度的一个很直观的想法是构建物品的内容特征,但是并不是在任何情况下都适用的,譬如对一段音乐一本图书等等,构建内容特征一来可解释性弱二来增大了计算复杂度。换个角度思考问题,如果两个物品总是被同时放入购物车那么这两个物品的相关性就会相当大,那么可以考虑使用频繁度来度量物品之间的相似性,例如:两物品同时出现的次数除以出现的总次数(刨去重叠的部分),用概率的语言来表述就是

p(AB)p(AB)


应该明白,对于相似度的度量有一些通用的选择,而对于特征的构建与选择应该是被重点关注与考量的,需要根据实际的场景作出选择。

推荐

      有了相似度,接下来选择最相似的几个用户或者物品就是顺理成章的事情了,这里介绍一种最简单最直白的算法——kNN算法。kNN算法是指从训练集中找到k个与给定样例最接近的对象,用在分类中是为了找到这k个对象的主导类别从而判断测试对象的类别——典型的近朱者赤近墨者黑。而在推荐中我们则不关心类别,我们只需要找到这k个最接近的对象即可。关于这个“接近”前面我们介绍了几种通用的相似度定义,无论使用哪一种,一旦确定之后就可以开始计算了,计算的方法很简单,遍历即可,就如同在海量数据中寻找最小的k个数一样。因为这里使用kNN的目的不是为了分类,所以对kNN不再作更多的展开,我们来考虑找到这k个对象以后的事情。 
      对于基于用户的协同过滤而言,这k个对象意味着兴趣和你最接近的k个朋友,翻翻他们喜欢的东西相信会有所收获。一般来说,系统里会有一张用户-物品的评分表,里面记录了用户对各种商品的喜好程度,这本身也是计算相似度所用到的一部分特征。这时候会有很多种推荐策略,比如让这k个朋友每人推荐部分商品,比如从这k个朋友的偏好中挑选出评价最高的几种等等。对于基于物品的推荐也是类似,譬如简单的推荐最相似的几个物品,譬如根据历史偏好对新物品进行评估后推荐。 
      同样,这里只是简单介绍一下基本的思路,对于实际应用的推荐仍然有很多细节地方未涉及到,将会在下一章进行详述。

 

冷启动

       在基于用户的协同过滤算法中需要计算用户之间的相似度,然而对一个新用户该如何提取特征呢?对于这个新用户,很有可能他的一些浏览记录、购买历史等信息都是为空的或者很稀少,这使得在寻找相似用户的过程中很难正确找到拥有相似喜好的人,或者找到一个其实相似度并不是很高的用户。这提醒我们,在利用相似度的时候可以设置一个最小阈值避免找到差异过大的邻居。另一方面,对于新用户或多或少会有一部分个人特征信息,同样可以根据这部分信息进行计算推荐:典型的如你附近的人都XXX,或者进行热门推荐,当然这可能带来较大的偏差,推荐效果有待商榷。 
       在基于物品的协同过滤算法中这个问题同样存在。如果按照上一篇文章的方法计算相似度,那么一个新的物品与其他任何一个物品的相似度都为零,因为没人购买过。解决的方案之一就是引入另外的相似度,譬如基于内容的相似度,这个相似度在最开始可以简单的考虑物品的分类属性(物品属于某一大类下的某一小类)从而避免复杂的特征提取。实际上在运用中往往都不是单一的使用某种推荐算法的,就像这样可以对两种相似度进行一个加权混合提高准确性。

拓展性与效率

       在基于用户的协同过滤推荐中需要计算用户之间的相似度,这涉及到用户-物品评分表,计算的复杂度是和这张表的规模紧密相关的,在不同的应用场景中会有比较大的差异。譬如在新闻媒体网站上,内容的更新是比较快的,新内容产出量非常大,进而导致物品的数量远比用户的数量大,而在一个电商网站上情况则可能相反,新的商品更新速度相对较慢。同时,对单一用户而言,其涉及到的商品数量在整个商品库中必定是只占很小一部分的,意味着数据极其稀疏,为了提高推荐效率与利用稀疏性,可以只考虑有过购买行为的物品,而无关物品则不参与计算。但相似度矩阵仍然是需要耗费大量计算资源,在实际生产使用时往往使用离线计算好的缓存。 
       实际上无论是采用哪种推荐算法都涉及到海量的用户、物品数据,推荐系统一方面要保证推荐质量,另一方面要保证实时数据的迅速计算,往往需要采用分层系统,其不再是单一的推荐系统而是多个系统的混合,在线端适当牺牲准确性来提高即时性,离线端则要保证算法的准确可靠,离线端的计算结果可以使用缓存技术为前端所用。

评分准则

       采用相似度的系统的一个前提是构建相关向量特征,特征构建的好坏直接决定了推荐结果的好坏。如何从用户的行为中挖掘用户的偏好特征呢?这取决于具体的应用场景,下面简单举个例子。还是以电商网站为例:

浏览次数:对一个商品浏览次数越多,说明关注度越高 
浏览时间(页面停留时间):同样的道理,停留时间长的说明关注度高 
评论浏览次数/条数:理由同上 
是否收藏/是否加入购物车/是否购买:理由仍然同上 

       可以看出用户大大小小的行为其实都隐含表达出某种偏好,而诸如此类的行为特征应该根据根据具体场景去发掘,一个好的推荐系统应该能根据点点蛛丝马迹准确识别用户的意图。同时也应该注意,在收集数据的时候要对其进行去噪处理:一个用户在某个页面停留的时间未必就是浏览时间,也许他只是离开了,数据中必然存在着噪声。

多样性

       一个好的推荐系统,不应该总是推荐一些你可能已熟知的物品,或者总是同一类的物品。典型的一个例子就是基于物品的协同过滤,因为是基于物品的相似度,那么它的推荐列表很有可能就是同一类别下的物品,这带来一个问题就是推荐列表内的物品间相似度较高:用户买了一把A牌子的菜刀,再给他推荐B、C、D牌子的菜刀显然是没什么意义的。因而需要进一步的筛选来降低列表内的相似度,买了菜刀配个砧板才是个好主意。 
       当使用基于相似用户的推荐时,其往往是倾向于热门推荐,因为热门商品受很多用户青睐。这可以通过某种混合手段来提高多样性:商品本身有其固有的分类属性,在进行推荐的时候需要考虑这一点,不能只考虑一个领域的商品,一种方法是在每个领域之中挑选几种与给定物品较相似的进行推荐。这不再是单纯的考虑物品的相似度,而是综合考虑了相似用户的偏好。

推荐阅读