上节课我们简单介绍了推荐系统的总体框架思路,从本节课开始我们将对推荐系统中的核心算法进行详细讲解。在目前主流的推荐算法中,使用最多也是最经典的,当属协同过滤算法!
1、什么是协同过滤
首先,我们还是简单介绍一下,什么是协同过滤。所谓协同过滤,它的基本思想是根据用户历史的喜好或者与目标用户兴趣相近的其他用户的选择来给目标用户推荐物品。也就是协同过滤中两种非常常用的算法:基于用户的协同过滤算法(User-CF)以及基于物品的协同过滤算法(Item-CF)。为了减轻大家的阅读压力,本文将重点先介绍基于用户的协同过滤算法(User-CF)。
2、基于用户的协同过滤算法
基于用户的协同过滤算法(下面简称User-CF算法)简单来说就是给用户推荐与他兴趣相似的其他用户喜欢的物品,例如,我和小明兴趣相似,都喜欢数码产品,那么当我在电商平台搜索某个数码产品时,电商平台就可以根据小明之前购买过的商品对我进行推荐,这背后的依据就是User-CF算法。聪明的同学可能已经发现,这其中的关键是相似性,也就是User-CF算法它如何度量我和小明之间的相似的呢?为什么它就能断定我是和小明相似,而不是与小王或者小李相似?那么接下来我们就详细介绍一下,到底在User-CF算法中是如何进行相似性度量的。
3、相似性度量
前面我们介绍过,协同过滤的基本思想是根据用户历史的喜好或者与目标用户兴趣相近的其他用户的选择来给目标用户推荐物品,那么用户的喜好可以从用户的历史行为,例如点击、购买、付费等信息中提取,也可以根据用户的基本属性,例如性别、年龄、职业等,甚至是用户当前所处的上下文环境中进行信息提取,得到这些信息之后我们稍作加工就可以进行用户相似性度量了,可以说这就是两个用户之间相似性度量的基本依据。而相似性度量的方法有很多,如余弦距离、欧式距离、Jaccard相似度等。下面我们就重点以余弦距离为例进行讲解。
首先回顾一下初中学过的知识:余弦值越小,其夹角越大;余弦值越大,其夹角越小。如下图所示。
余弦距离公式:
例如A(2,2,1),B(1,1,0),根据余弦距离公式,得到
分子:2*1 2*1 1*0=4
分母:sqrt(2^2 2^2 1^2) * sqrt(1^2 1^2 0^2) = 3*sqrt(2)
故A与B之间的余弦相似性为4/(3*sqrt(2))=0.94
那么回到前面的问题,为什么电商平台要推荐小明购买过的商品给我,而不是推荐小王或者小李购买过的商品给我呢?原来电商平台是通过平台历史用户对购买过的商品评分信息,计算出我与小明之间的相似性最高,所以将小明购买过的鼠标和显示器推荐给了我(这两种商品我之前都没有购买过)。其具体计算过程如下所示:
笔记本电脑 | 鼠标 | 键盘 | 鼠标垫 | 显示器 | |
---|---|---|---|---|---|
我 | 5 | 1 | 2 | ||
小明 | 4 | 3 | 2 | 1 | |
小王 | 2 | 4 | 1 | 1 | |
小李 | 2 | 5 |
注:表中的数值表示每个用户对购买过的商品的评分,表格中缺失的评分表示用户未对商品进行评分(默认为用户未发生过购买行为的商品),暂时认为缺失的数据都为0。
那么可以分别得到用户对物品之间的几组评分向量(5,0,1,2,0)、(4,3,2,0,1)、(2,4,0,1,1)、(0,2,5,0,0)
那么我(5,0,1,2,0)与小明(4,3,2,0,1)之间的余弦值为
分子:5*4 0*3 1*2 2*0 0*1=22
分母:sqrt(5*5 0 1*1 2*2 0)*sqrt(4*4 3*3 2*2 0 1*1)
即
5*4 0*3 1*2 2*0 0*1/(sqrt(5*5 0 1*1 2*2 0)*sqrt(4*4 3*3 2*2 0 1*1))=0.73
同理可以计算得到我与小王,小李之间的余弦值分别为:0.46、0.17。
得到最终的余弦值大小排序:0.73>0.46>0.17。
综上可以知道我与小明之间的余弦值最大,表示余弦夹角最小,我们之间最相似,故电商平台会把小明买过而我没买过的商品推荐给我,这就是采用了User-CF算法原理进行用户之间的商品推荐。
4、总结
以上就是User-CF算法的全部原理的详细讲解,希望对大家有帮助,最后附上User-CF实现的核心代码模块,有兴趣的同学可以手动去尝试实现,下节课给大家带来基于物品的协同过滤算法(Item-CF),敬请期待
代码语言:javascript复制def SimliarUser(self,username,type,n=1):
distances={}; #用户,相似度之间以字典形式存储
for otherUser,items in self.data.items():#遍历整个数据集
if otherUser != username:#非当前的用户
distance=self.getDistance(self.data[username],self.data[otherUser],type)#计算两个用户的相似度,采用余弦距离
distances[otherUser]=distance
sortedDistance=sorted(distances.items(),key=operator.itemgetter(1),reverse=True);#最相似的N个用户
#print ("排序后的用户为:",sortedDistance)
return sortedDistance[:n]
#给用户推荐物品
def Recomand(self,username,n=1):
recommand={};#待推荐的物品
for user,score in dict(self.SimliarUser(username,n)).items():#最相近的n个用户
#print ("推荐的用户:",(user,score))
for goods,scores in self.data[user].items():#推荐的用户的物品列表
if goods not in self.data[username].keys():#当前username没有购买过
#print ("%s为该用户推荐的物品:%s"%(user,goods))
if goods not in recommand.keys():#添加到推荐列表中
recommand[goods]=scores
return sorted(recommand.items(),key=operator.itemgetter(1),reverse=True);