协同过滤推荐算法

本文介绍协同过滤推荐系统的基本原理,并通过实例演示了基于用户和基于物品的推荐算法。包括使用欧几里德距离及皮尔逊相关系数计算用户间的相似度,以及如何依据这些相似度给出推荐。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简单的理解协同过滤: 相似兴趣爱好的人喜欢相似的东西,具有相似属性的物品可以推荐给喜欢同类物品的人。比如,user A喜欢武侠片,user B也喜欢武侠片,那么可以把A喜欢而B没看过的武侠片推荐给B,反之亦然,这种模式称为基于用户的协同过滤推荐(User-User Collaborative Filtering Recommendation);再比如User A买了《java 核心技术卷一》,那么可以推荐给用户《java核心技术卷二》《java编程思想》,这种模式称为基于物品的协同过滤(Item-Item Collaborative Filtering Recommendation).
下面是亚马逊中查看《java核心技术卷一》这本书的推荐结果:
这里写图片描述

下面参考《集体智慧编程》一书,实现基于欧几里德距离和基于皮尔逊相关度的用户相似度计算和推荐。

数据集,用户对电影的打分表:

moviesLady in the WaterSnakes on a PlaneJust My LuckSuperman ReturnsYou, Me and DupreeThe Night Listener
Lisa2.53.53.03.52.53.0
Gene3.03.51.55.03.53.0
Michael2.53.03.54.0
Claudia3.53.04.02.54.5
Mick3.04.02.03.02.0
Jack3.04.05.03.53.0
Toby4.54.01.0

建立数据字典


critics={'Lisa': {'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': {'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': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0,
 'Superman Returns': 3.5, 'The Night Listener': 4.0},
'Claudia': {'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': {'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': {'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}}

欧几里德距离


#返回一个有关person1与person2的基于距离的相似度评价
def sim_distance(prefs, person1, person2):

  #得到shared_item的列表
  ci = {}
  for item in prefs[person1]:
    if item in prefs[person2]:
      ci[item] = prefs[person1][item] - prefs[person2][item]

  if len(ci) == 1:  # confuses pearson metric
    return sim_distance(prefs, person1, person2)

  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))

计算Lisa和Gene之间的欧式距离:

print(sim_distance(critics,'Lisa','Gene'))

结果:

0.294298055086

皮尔逊相关系数

#返回一个有关person1与person2的基于皮尔逊相关度评价
def sim_pearson(prefs,p1,p2):
  # Get the list of mutually rated 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

  # Sum calculations
  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]) 

  # Sum 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

计算Lisa和Gene之间的皮尔逊相关系数:

print(sim_pearson(critics,'Lisa','Gene'))

结果:

0.396059017191

选择Top N

 # 从反应偏好的字典中返回最为匹配者
 # 返回结果的个数和相似度函数均为可选参数
def topMatches(prefs, person, n=5, similarity=sim_pearson):
  scores = [(similarity(prefs, person, other), other)
      for other in prefs if other != person]
  scores.sort(reverse=True)
  return scores[0:n]

返回4个和Toby品味最相似的用户:

print(topMatches(critics,'Toby',n=4))

结果:

yaopans-MacBook-Pro:ucas01 yaopan$ python  recommend.py 
[(0.9912407071619299, 'Lisa'), (0.9244734516419049, 'Mick'), (0.8934051474415647, 'Claudia'), (0.66284898035987, 'Jack')]

基于用户推荐

def getRecommendations(prefs,person,similarity=sim_pearson):
  totals={}
  simSums={}
  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:
        # 相似度*评价值
        totals.setdefault(item,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

给Toby推荐:

print(getRecommendations(critics,'Toby'))

推荐结果

yaopans-MacBook-Pro:ucas01 yaopan$ python  recommend.py 
[(3.3477895267131013, 'The Night Listener'), (2.8325499182641614, 'Lady in the Water'), (2.5309807037655645, 'Just My Luck')]

基于物品推荐

基于物品推荐和基于用户推荐类似,把物品和用户调换。
转换函数:

def transformPrefs(prefs):
  result={}
  for person in prefs:
    for item in prefs[person]:
      result.setdefault(item,{})
      result[item][person]=prefs[person][item]
  return result

返回和Superman Returns相似的电影:

movies=transformPrefs(critics)
print("和Superman Returns相似的电影:")
print(topMatches(movies,'Superman Returns'))

结果:

[(0.6579516949597695, 'You, Me and Dupree'), (0.4879500364742689, 'Lady in the Water'), (0.11180339887498941, 'Snakes on a Plane'), (-0.1798471947990544, 'The Night Listener'), (-0.42289003161103106, 'Just My Luck')]

结果为负的是最不相关的。
代码下载地址:
recommend.py

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

esc_ai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值