吉吉于

free

基于用户的协作型过滤推荐系统

前一节的《欧几里德距离和皮尔逊相关系数》里使用欧几里得距离还有皮尔逊相关系数计算了两个用户品味相似度。

这一节继续完善代码,添加了与用户兴趣相投的用户排行榜,给用户推荐喜好的电影。

代码:

# A dictionary of movie critics and their ratings of a small
# set of movies
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}}

from math import sqrt

# Returns a distance-based similarity score for person1 and person2
def sim_distance(prefs, person1, person2):

  # Get the list of shared_items
  si = {}
  for item in prefs[person1]:
    if item in prefs[person2]:
      si[item] = 1

  # if they have no ratings in common, return 0
  if len(si) == 0: 
    return 0 

  # Add up the squares of all the differences
  sum_of_squares=sum([pow(prefs[person1][item]-prefs[person2][item],2) 
                      for item in prefs[person1] if item in prefs[person2]])

  return 1/(1+sqrt(sum_of_squares))

def sim_pearson(prefs, p1, p2):
  #Get the list of mutually rated shared_items
  si = {}
  for item in prefs[p1]:
    if item in prefs[p2]:
      si[item] = 1

  # if they are no ratings in common, return 0
  if len(si) == 0:
    return 0

  n = len(si)

  # Sums of all the preferences
  sum1 = sum([prefs[p1][it] for it in si])
  sum2 = sum([prefs[p2][it] for it in si])

  # Sums of the squares
  sum1Sq = sum([pow(prefs[p1][it],2) for it in si])
  sum2Sq = sum([pow(prefs[p2][it],2) for it in si])

  # Sums of the products
  pSum = sum([prefs[p1][it]*prefs[p2][it] for it in si])

  # Calculate r (Pearson score)
  num = pSum - (sum1*sum2/n)
  den = sqrt((sum1Sq-pow(sum1,2)/n)*(sum2Sq-pow(sum2,2)/n))
  if den == 0:
    return 0

  r = num / den
  return r

# Returns the best matches for person from the prefs dictionary. 
# Number of results and similarity function are optional params.
def topMatches(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]

# Gets recommendations for a person by using a weighted average
# of every other user's rankings
def getRecommendations(prefs,person,similarity=sim_pearson):
  totals={}
  simSums={}
  for other in prefs:
    # don't compare me to myself
    if other==person: continue
    sim=similarity(prefs,person,other)

    # ignore scores of zero or lower
    if sim<=0: continue
    for item in prefs[other]:

      # only score movies I haven't seen yet
      if item not in prefs[person] or prefs[person][item]==0:
        # Similarity * Score
        totals.setdefault(item,0)
        totals[item]+=prefs[other][item]*sim
        # Sum of similarities
        simSums.setdefault(item,0)
        simSums[item]+=sim

  # Create the normalized list
  rankings=[(total/simSums[item],item) for item,total in totals.items()]

  # Return the sorted list
  rankings.sort()
  rankings.reverse()
  return rankings

以上代码保存为r.py

运行:

1。和Toby品味相投的用户

2。给Toby推荐的电影

reload(r)

<module ‘r’ from ‘r.py’>

r.topMatches(r.critics,’Toby’,n=3)
[(0.9912407071619299, ‘Lisa Rose’), (0.9244734516419049, ‘Mick LaSalle’), (0.8934051474415647, ‘Claudia Puig’)]
reload(r)

<module ‘r’ from ‘r.py’>

r.getRecommendations(r.critics,’Toby’)
[(3.3477895267131013, ‘The Night Listener’), (2.8325499182641614, ‘Lady in the Water’), (2.5309807037655645, ‘Just My Luck’)]

转载请注明:于哲的博客 » 基于用户的协作型过滤推荐系统