一、背景
关于推荐算法的相关背景介绍,已经在上一个姊妹篇(三)协同过滤算法之基于物品的推荐算法python实现中有所介绍。在此,便不在赘述,本文主要介绍基于用户的协同过滤算法,而对推荐算法不太清楚的朋友们可以参考上一篇基于物品的过滤算法的相关介绍,参考地址如下:https://blog.csdn.net/wickedvalley/article/details/79927699。
二、生活应用
推荐算法应用比较广,常见的就是推荐电影了,上一篇是基于物品的推荐算法,主要是根据物品的相似度来进行推荐。本文的推荐算法是基于用户的推荐,原理也是类似的,主要是计算出与当前需要推荐用户的最相似用户,从而根据最相似的用户喜欢的物品来推荐当前可能喜欢的物品。
还是以电影推荐为例子,见下图:
说明:
三个用户分别为A用户、B用户、C用户。他们看过的电影如上图所示,他们看过的电影中,既有相同的,也有不同的。我们需要计算与待推荐的用户A与所有的用户的相似度,进而找到与A用户最相似的N个用户,假设N=1,则需要找到与A用户最相思的1个用户,如上图,可以找到B用户与A用户是最相似的,从而将B看过而A没有看过的《机器猫》推荐给A用户。
四、相似度计算
相似度的计算有欧式距离、皮尔逊相关系数等,本文主要介绍皮尔逊相关系数。
Pearson相关系数用来衡量两个数据集合之间的相似性。比如在一个关于电影的资料网站中,很多用户都可能对其中的电影进行打分。Pearson相关系数可以用来帮助更好的找到兴趣相似的用户,从而进行相关的推荐。这种推荐的基本思路是如果A和B兴趣相似,那么A喜欢看的,B就有很大可能会喜欢看,就可以把A的喜欢看的推荐给B。
假设电影库中5部电影,A和B都对其中的部分进行了打分(5分为满分),A的分数是[3, 2, -, 1, 4],B的分数是[5, 3, 3, -, 5],其中“-”表示未打分。那么A和B的Pearson相关系数是0.866,说明两个人的兴趣是比较相似的。
Pearson相关系数的一个优点是可以避免评分等级膨胀(grade inflation)的问题,也就是说有的用户可能倾向于对所有的电影都给比较高的分数,而有的用户则会比较苛刻,给分都比较低。对于这种情况,Pearson相关系数可以处理。
Pearson相关系数的具体计算公式为:
五、算法流程:
1.根据当前用户,计算与当前用户最相似的N个用户;
2.推荐这N个最相似的用户看过的电影(排除当前用户观看过的)
3.将所有当前用户没有看过的电影,按照评分从高到低推荐给用户
六、python实现算法
1.数据描述
数据为用户,以及用户观看的电影,评分。
如下:用户Lisa Rose 看过的电影以及相应的评分为’Lady in the Water’: 2.5,’Snakes on a Plane’: 3.5 …..
users = {'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,
'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5,
'The Night Listener': 3.0},
'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5,
'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 3.5},
'Michael Phillips': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0,
'Superman Returns': 3.5, 'The Night Listener': 4.0},
'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0,
'The Night Listener': 4.5, 'Superman Returns': 4.0,
'You, Me and Dupree': 2.5},
'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 2.0},
'Jack Matthews': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5},
'Toby': {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 'Superman Returns': 4.0}
}
2.目标
给用户Toby推荐可能感兴趣的电影
3.算法实现
#!/usr/bin/python
# -*- coding: UTF-8 -*-
'''
基于用户的推荐算法
'''
from math import sqrt,pow
import operator
class UserCf():
#获得初始化数据
def __init__(self,data):
self.data=data;
#通过用户名获得电影列表,仅调试使用
def getItems(self,username1,username2):
return self.data[username1],self.data[username2]
#计算两个用户的皮尔逊相关系数
def pearson(self,user1,user2):#数据格式为:电影,评分 {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 'Superman Returns': 4.0}
sumXY=0.0;
n=0;
sumX=0.0;
sumY=0.0;
sumX2=0.0;
sumY2=0.0;
try:
for movie1,score1 in user1.items():
if movie1 in user2.keys():#计算公共的电影的评分
n+=1;
sumXY+=score1*user2[movie1]
sumX+=score1;
sumY+=user2[movie1]
sumX2+=pow(score1,2)
sumY2+=pow(user2[movie1],2)
molecule=sumXY-(sumX*sumY)/n;
denominator=sqrt((sumX2-pow(sumX,2)/n)*(sumY2-pow(sumY,2)/n))
r=molecule/denominator
except Exception,e:
print "异常信息:",e.message
return None
return r
#计算与当前用户的距离,获得最临近的用户
def nearstUser(self,username,n=1):
distances={};#用户,相似度
for otherUser,items in self.data.items():#遍历整个数据集
if otherUser not in username:#非当前的用户
distance=self.pearson(self.data[username],self.data[otherUser])#计算两个用户的相似度
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.nearstUser(username,n)).items():#最相近的n个用户
print "推荐的用户:",(user,score)
for movies,scores in self.data[user].items():#推荐的用户的电影列表
if movies not in self.data[username].keys():#当前username没有看过
print "%s为该用户推荐的电影:%s"%(user,movies)
if movies not in recommand.keys():#添加到推荐列表中
recommand[movies]=scores
return sorted(recommand.items(),key=operator.itemgetter(1),reverse=True);#对推荐的结果按照电影评分排序
if __name__=='__main__':
users = {'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,
'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5,
'The Night Listener': 3.0},
'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5,
'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 3.5},
'Michael Phillips': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0,
'Superman Returns': 3.5, 'The Night Listener': 4.0},
'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0,
'The Night Listener': 4.5, 'Superman Returns': 4.0,
'You, Me and Dupree': 2.5},
'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 2.0},
'Jack Matthews': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5},
'Toby': {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 'Superman Returns': 4.0}
}
userCf=UserCf(data=users)
recommandList=userCf.recomand('Toby', 2)
print "最终推荐:%s"%recommandList
4.算法结果
排序后的用户为: [('Lisa Rose', 0.9912407071619299), ('Mick LaSalle', 0.9244734516419049), ('Claudia Puig', 0.8934051474415647), ('Jack Matthews', 0.66284898035987), ('Gene Seymour', 0.38124642583151164), ('Michael Phillips', -1.0)]
推荐的用户: ('Lisa Rose', 0.9912407071619299)
Lisa Rose为该用户推荐的电影:Lady in the Water
Lisa Rose为该用户推荐的电影:Just My Luck
Lisa Rose为该用户推荐的电影:The Night Listener
推荐的用户: ('Mick LaSalle', 0.9244734516419049)
Mick LaSalle为该用户推荐的电影:Lady in the Water
Mick LaSalle为该用户推荐的电影:Just My Luck
Mick LaSalle为该用户推荐的电影:The Night Listener
最终推荐:[('Just My Luck', 3.0), ('The Night Listener', 3.0), ('Lady in the Water', 2.5)]