上一篇中介绍了四个算法,并用四个算法分别计算了两个人的相似度。这篇就来讲讲相似性算法在实际当中怎么用。第一:将指定的人与其他人作相似性比较,并从高到低进行排序;第二:对指定的人推荐未看过的电影。同样还是先给出具体分析,然后给出相应算法,再最后一起给出代码。
根据相似性从高到底排序。
def topMatchs(prefs, person, n=5, similarity=sim_pearson): scores=[(similarity(prefs, person, other), other) for other in prefs if other!=person] scores.sort() scores.reverse() return scores[0:n]
以上是这一部分的算法。其中涉及到Python的函数式编程,由于我也是才在学Python,所以在以后也会顺带解释相应的Python代码,topMatchs方法一共有四个参数,第一、二个参数是必传的参数,第三、四是选传的参数,如果不传入参数,则传入其默认的值,注意第四个参数传入的是一个函数,所以将函数作为一个参数来进行传递也就是函数式编程,sim_pearson方法在上一篇中有相应代码,在本文末也有相应代码。这个算法比较简单,就是指定一人与每个人进行相似性度量,讲比较的结果存入一个list,然后进行排序、返回。
推荐未看过的电影。
def getRecommendations(prefs, person, similarity=sim_pearson): totals = { } #与指定人(person)的相似度 x 对person未看过电影的评分(加权值)。所有人的总和 simSums = { } #所有人的相似度(是对该电影有过评价且对person来说未看过的人) # for other in prefs: if other == person: continue #肯定不和自己比较 sim = similarity(prefs, person, other) #返回的是与此人的相似度 #忽略相似度为0或者小于0的情况, if sim <= 0: continue for item in prefs[other]: #只对自己还未看过的电影进行推荐 if item not in prefs[person] or prefs[person][item] == 0: #相似度 x 对该电影的评论 totals.setdefault(item, 0) #该方法是Dictionary方法,若键key不存在于此Dictionary中,将会添加该键到Dictionary中,并设默认值(0) totals[item] += prefs[other][item] * sim #相似度之和 simSums.setdefault(item, 0) simSums[item] += sim rankings = [(total/simSums[item], item) for item, total in totals.items()] rankings.sort() rankings.reverse() return rankings
这个算法有两点,第一:未看过的电影,这个好解决。第二:推荐,怎么个推荐?是否能根据某一个人和我的相似度很高,所以就将他看过我没看过的电影推荐给我?当然不行,就算他和我相似度很高,但是还是存在他对某一部电影的评分很低,而我又没有看过就推荐给我,所以单单从某人和我的相似度高低这一个因素来进行显然不可以。同样存在某一个人一部电影的评分很高,但他的相似度和我很低,而且其他人对此电影的评分很低,这种情况也不可以。所以引用原文中的话“我们需要通过一个经过加权的评价值来为影片打分”。我们还是按照上周给出过的例子,小明A对《左耳》、《何以笙箫默》、《速度与激情》的评分分别是3、4、5,小红对这三部电影的评分是2、5、1,再加上“我”。我们假设这三部电影我没有看过,根据上面一个算法得出A对我的相似度是0.99,B是0.38。现在列出一个表格来进行说明。
。每个电影的评价值,也就是经过加权后的评价值=相似度x对该电影的评分。Total代表每个电影的经过加权后评价值总和,相似度总和则是所有评论者的相似度总和,最后Total/相似度总和即得到影片的推荐值,由此可见推荐度分别是《何以》、《速度》、《左耳》。注意,这里的所有评论者指的都是评论过该电影的评论者,若没有评论过该电影者,Total和相似度总和都不包括此人。如果想要更加详细的了解,请参阅中文版《集体智慧编程》P15。我认为最关键的地方在于——加权,如何加权,怎么加权合适,这是个问题。
下面就贴出所有的代码,只需要将以下代码直接贴在上章的最后即可。
1 #指定一人与其他人的相似度排名 2 def topMatchs(prefs, person, n=5, similarity=sim_pearson): 3 scores=[(similarity(prefs, person, other), other) for other in prefs if other!=person] 4 5 scores.sort() 6 scores.reverse() 7 return scores[0:n] 8 9 print u"与Toby相似度最高的人" 10 print topMatchs(critics, 'Toby', n=3) 11 12 #以下方法在topMatchs方法的基础上直接根据相似度x加权值(对每个电影的评分)推荐电影 13 def getRecommendations(prefs, person, similarity=sim_pearson): 14 totals = { } #与指定人(person)的相似度 x 对person未看过电影的评分(加权值)。所有人的总和 15 simSums = { } #所有人的相似度(是对该电影有过评价且对person来说未看过的人) 16 # 17 for other in prefs: 18 if other == person: continue #肯定不和自己比较 19 sim = similarity(prefs, person, other) #返回的是与此人的相似度 20 21 #忽略相似度为0或者小于0的情况, 22 if sim <= 0: continue 23 24 for item in prefs[other]: 25 #只对自己还未看过的电影进行推荐 26 if item not in prefs[person] or prefs[person][item] == 0: 27 #相似度 x 对该电影的评论 28 totals.setdefault(item, 0) #该方法是Dictionary方法,若键key不存在于此Dictionary中,将会添加该键到Dictionary中,并设默认值(0) 29 totals[item] += prefs[other][item] * sim 30 #相似度之和 31 simSums.setdefault(item, 0) 32 simSums[item] += sim 33 34 rankings = [(total/simSums[item], item) for item, total in totals.items()] 35 36 rankings.sort() 37 rankings.reverse() 38 return rankings 39 40 print u"推荐给Toby的电影" 41 print getRecommendations(critics, "Toby")
在这章中,相似性度度量算法使用了“皮尔逊相关系数”,书中提到“选择不同的相似性度量方法,对结果的影响是微乎其微的”。事实的确如此,使用上章的四个算法,影片的推荐都是一致的。