吉吉于

基于物品的过滤

前三节我们陆续的写了一个基本的小引擎,使用每一位用户的全部评分构造数据集。

想象一下,如果拿大数据来使用它来分析,推荐,将一个用户和所有其他用户进行比较,然后对每位用户评过分的商品进行比较,速度可想而知。前几说的是”基于用户的协作型过滤”(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’)]

转载请注明:于哲的博客 » 基于物品的过滤