社会化协作过滤-推荐系统主要是干什么的?比如十个人中,每个人都对几部电影打了分数,然后选择一个我们要推荐的对象,然后对另外的9个人进行比较,然后用欧几里的距离计算推荐对象与另外对象的相似度,然后我们给定一个阀值,比如归一化处理以后我们定位0.5,只要另外的对象相似度大于0.5的我们就把这个对象定义为推荐对象的相似用户,存入到数组中,然后可以通过这些相似用户来推断我们推荐对象对某个没看过电影的评分是多少。
所以这个推荐系统我们要先知道欧几里的距离是干啥的,并且怎么计算? 主要还是把它还原成一个二维表中,计算一个坐标系中两个点之间的距离。
Python测试代码如下:
# 欧几里得距离 差值的平方和的平方根
from math import sqrt
sqrt( pow( (4.5-4.0),2 )+pow( (1.0-2.0),2 ) ) #1000,1000000 归一化:将值归一到0到1之间
对于我们这个项目,我们不能直接使用欧几里得距离,因为这个距离不固定,可以一直到无穷大,不是很好判断,所以对于这个系统,我们要进行归一化处理,
1 / ( 1 + sqrt( pow( (4.5-4.0),2 )+pow( (1.0-2.0),2 ) ) ) #归一化处理:0表示两人完全不同, 1表示完全相同 把可能无穷大的值转化到0-1之间
测试数据:
critics={'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}}
一、定义一个函数,获取两个用户共同评分项:
-
#定义函数 : 获取两个用户共同评分项 def getSameItem( prefs,person1,person2 ): #prefs表示传进来的 critics 数据,person1与2表示要比较的两个人 shared_items={} #一个键值对 for item in prefs[person1]: if item in prefs[person2]: #判断person1中的一部电影是否和 person2 中的某一部电影锲合 shared_items[item]=1 return shared_items getSameItem(critics,'Lisa Rose','Gene Seymour')
执行输出:{'Just My Luck': 1,
'Lady in the Water': 1,
'Snakes on a Plane': 1,
'Superman Returns': 1,
'The Night Listener': 1,
'You, Me and Dupree': 1}
二、计算这两个用户的相似度,也就使用了我们上面的欧几里得距离
#定义函数:计算两个人的相似度: 基于欧几里得距离
def sim_Euclid( prefs,person1,person2 ):
#1.取共同的评分项
#2.如果 返回的共同项为0,则相似度为0
#3.计算欧几里的距离
#4.归一化处理
#5.返回值
shared_items = getSameItem( prefs,person1,person2 ) #使用这个来判断这两个所比较的对象是否有评分项
if len( shared_items )==0: #说明比较的两人没有相同的评分项,直接返回0
return 0;
distance = sqrt( sum( [ pow( prefs[person1][item]-prefs[person2][item],2 ) for item in prefs[person1] if item in prefs[person2] ] ) )#计算欧几里的距离
guiyi = 1/(1+distance)
return guiyi
T_M = sim_Euclid(critics,'Toby','Mick LaSalle')
print(T_M)
L_G = sim_Euclid(critics,'Lisa Rose','Gene Seymour')
print(L_G)
执行输出:
0.4
0.29429805508554946
三、计算各个用户的相似度后,返回与某个用户相似的前N个用户
#定义函数: 返回与某个用户相似的前N个用户
def topMatches(prefs,person,n=5,similarity=sim_Euclid):
#计算分数
arr=[ ( similarity(prefs,person,other),other ) for other in prefs if other!=person ]
print(arr)
arr.sort() #比较顺序,从每个元素按位置来排序
arr.reverse()
return arr[:n]
topMatches(critics,'Toby',n=3)
执行输出:
[(0.3483314773547883, 'Lisa Rose'), (0.38742588672279304, 'Michael Phillips'), (0.4, 'Mick LaSalle'), (0.2674788903885893, 'Jack Matthews'), (0.25824569976124334, 'Gene Seymour'), (0.3567891723253309, 'Claudia Puig')]
Out[9]:[(0.4, 'Mick LaSalle'),
(0.38742588672279304, 'Michael Phillips'),
(0.3567891723253309, 'Claudia Puig')]
四、使用前三点我们写好的函数来实现最后的功能,预估某用户对没看过的电影的评分
#升级推荐: 社会化协同过滤 目标:根据用户相似度去计算 一个用户有可能对某个电影的评分
def getRecommendation( prefs,person,similarity=sim_Euclid ):
total={} # {电影名,加权平分和}
simSums = {}
#开始计算相似度
for other in prefs:
if other==person: #避免自己与自己比较,造成误差
continue
sim = similarity(prefs,person,other) #参数中 赋值为sim_Euclid,计算欧几里得距离
#找 other看过,但是person没有看过的电影
for item in prefs[other]:
if item not in prefs[person] or prefs[person][item]==0:
#加权平分和
total.setdefault(item,0) # setdefault(item,0) 函数->添加一个键值对
total[item] += prefs[other][item]*sim
#相似度和
simSums.setdefault( item,0 )
simSums[item] += sim
result = [ (tot/simSums[item],item) for item,tot in total.items() ]
result.sort()
result.reverse()
return result[:15]
getRecommendation(critics,'Toby')
执行输出:
[(3.457128694491423, 'The Night Listener'), (2.778584003814924, 'Lady in the Water'), (2.4224820423619167, 'Just My Luck')]