基于物品的过滤
03 Dec 2012前三节我们陆续的写了一个基本的小引擎,使用每一位用户的全部评分构造数据集。
想象一下,如果拿大数据来使用它来分析,推荐,将一个用户和所有其他用户进行比较,然后对每位用户评过分的商品进行比较,速度可想而知。前几说的是”基于用户的协作型过滤”(user-based collaborative filtering)还有一种就是今天讲的”基于物品的过滤”(item-based collaborative filtering).在大数据集的情况下,基于物品的协作型过滤能够得出更好的结论,而且允许我们将大量的计算任务预先执行,从而给要推荐的用户更快的结果。
具体思路:
为每件物品预先计算好最为相近的其他物品。然后,当我们想为某用户推荐时,就可以查看他曾经评过分的物品,从中选出排名靠前着,然后构造一个加权列表,其中包含了与这些选中物品最为相近的其他物品。
区别:
无需不停的计算与每样物品最为相近的其他物品,可以用于网络流量小的时候,或者独立于主应用之外的另一台计算机上单独运行。
介绍完毕,下边开始动手~
为了对物品进行比较,我们编写一个函数,构造一个包含相近物品的完整数据集。这项工作无需在每次提供推荐时都做一遍,相反的是,构建完一次数据集之后,我们就可以在需要的时候重复使用它。
将以下函数加入r.py中(r.py在前几节已经写出,稍微我会贴过来)
def transformPrefs(prefs): result={} for person in prefs: for item in prefs[person]: result.setdefault(item,{}) # Flip item and person result[item][person]=prefs[person][item] return result def calculateSimilarItems(prefs,n=5): # Create a dictionary of items showing which other items they # are most similar to. result={} # Invert the preference matrix to be item-centric itemPrefs=transformPrefs(prefs) c=0 for item in itemPrefs: # Status updates for large datasets c+=1 if c%100==0: print "%d / %d" % (c,len(itemPrefs)) # Find the most similar items to this one scores=topMatches(itemPrefs,item,n=n,similarity=sim_distance) result[item]=scores return result
其中transformPrefs函数是将数据集以电影名称为中心进行倒置(之前是以用户为中心),得到一个物品以及用户评价的数据集。
然后使用calculateSimilarItems构造一个物品相似度的数据集:
import r
itemsim=r.calculateSimilarItems(r.critics)
itemsim
{‘Lady in the Water’: [(0.4494897427831781, ‘You, Me and Dupree’), (0.38742588672279304, ‘The Night Listener’), (0.3483314773547883, ‘Snakes on a Plane’), (0.3483314773547883, ‘Just My Luck’), (0.2402530733520421, ‘Superman Returns’)], ‘Snakes on a Plane’: [(0.3483314773547883, ‘Lady in the Water’)……
现在我们可以不用遍历数据集就能获得物品的相似物品,我们可以找出用户评价过的所有物品,找出其相似物品,根据相似度进行加权。
推荐物品,加入以下代码:
def getRecommendedItems(prefs,itemMatch,user): userRatings=prefs[user] scores={} totalSim={} # Loop over items rated by this user for (item,rating) in userRatings.items( ): # Loop over items similar to this one for (similarity,item2) in itemMatch[item]: # Ignore if this user has already rated this item if item2 in userRatings: continue # Weighted sum of rating times similarity scores.setdefault(item2,0) scores[item2]+=similarity*rating # Sum of all the similarities totalSim.setdefault(item2,0) totalSim[item2]+=similarity # Divide each total score by total weighting to get an average rankings=[(score/totalSim[item],item) for item,score in scores.items( )] # Return the rankings from highest to lowest rankings.sort( ) rankings.reverse( ) return rankings
运行结果:
r.getRecommendedItems(r.critics,itemsim,’Toby’)
[(3.1667425234070894, ‘The Night Listener’), (2.936629402844435, ‘Just My Luck’), (2.868767392626467, ‘Lady in the Water’)]