现在的位置: 首页 > 综合 > 正文

Programming Collective Intelligence 推荐系统 读书笔记二

2014年01月11日 ⁄ 综合 ⁄ 共 4410字 ⁄ 字号 评论关闭
 这章主要讲了如何做推荐,现在推荐最常用的几种算法:Collaborative Filtering、Cluster Models、Search-Based Methods、Item-to-Item Collaborative Filtering.前两种是通过找相似的Customer,后两种通过找相似的Item.论文Amazon.com Recommendations Item-to-Item Collaborative Filtering 对这几种算法都有介绍。这章主要提了Collaborative Filtering和tem-to-Item Collaborative Filtering。 Collaborative Filtering:通过搜索大量的Customer数据集来找到那一小撮和你口味相似的。书中举了一个电影评论的例子,每个人都对一些电影进行评等级,通过这些数据来找到和你口味相似的人,以及对你没有看过的电影做推荐,并以这个例子演示了如何做推荐。

准备数据:(本笔记的代码使用ruby实现,python代码的实现见原书)

Ruby代码 复制代码
  1. critics={  
  2.     'Lisa Rose' => {'Lady in the Water' => 2.5, 'Snakes on a Plane' => 3.5,  
  3.     'Just My Luck' => 3.0, 'Superman Returns' => 3.5, 'You, Me and Dupree' => 2.5,  
  4.     'The Night Listener' => 3.0},  
  5.   
  6.     'Gene Seymour' => {'Lady in the Water' => 3.0, 'Snakes on a Plane' => 3.5,  
  7.     'Just My Luck' => 1.5, 'Superman Returns' => 5.0, 'The Night Listener'=> 3.0,  
  8.     'You, Me and Dupree' => 3.5},  
  9.   
  10.     'Michael Phillips' => {'Lady in the Water' => 2.5, 'Snakes on a Plane' => 3.0,  
  11.     'Superman Returns' => 3.5, 'The Night Listener' => 4.0},  
  12.   
  13.     'Claudia Puig' => {'Snakes on a Plane' => 3.5, 'Just My Luck' => 3.0,  
  14.     'The Night Listener' => 4.5, 'Superman Returns' => 4.0,  
  15.     'You, Me and Dupree' => 2.5},  
  16.   
  17.     'Mick LaSalle'=> {'Lady in the Water' => 3.0, 'Snakes on a Plane' => 4.0,  
  18.     'Just My Luck' => 2.0, 'Superman Returns' => 3.0, 'The Night Listener' => 3.0,  
  19.     'You, Me and Dupree' => 2.0},  
  20.   
  21.     'Jack Matthews'=> {'Lady in the Water' => 3.0, 'Snakes on a Plane' => 4.0,  
  22.     'The Night Listener'=> 3.0, 'Superman Returns'=> 5.0, 'You, Me and Dupree' => 3.5},  
  23.   
  24.     'Toby' => {'Snakes on a Plane' =>4.5,'You, Me and Dupree' =>1.0,'Superman Returns' => 4.0}  
  25. }  

 

定义相似度:

欧拉距离:

 

 

 

代码实现:

 

Ruby代码 复制代码
  1. def sim_distance(prefs,person1,person2)  
  2.     si = {}  
  3.     prefs[person1].each_key do |item|  
  4.         si[item] = 1 if prefs[person2][item]  
  5.     end  
  6.       
  7.     return 0 if si.empty?  
  8.       
  9.     sum_of_squares = si.keys.inject(0) do |sum,item|  
  10.         sum + (prefs[person1][item] - prefs[person2][item]) ** 2  
  11.     end  
  12.     
  13.     return 1 / (1 + sum_of_squares)  
  14. end  

 

 

 Pearson Correlation Score:

 

代码实现:

 

Ruby代码 复制代码
  1. def sim_pearson(prefs,person1,person2)  
  2.     si = {}  
  3.     prefs[person1].each_key do |item|  
  4.         si[item] = 1 if prefs[person2][item]  
  5.     end  
  6.     
  7.     return 0 if si.empty?  
  8.     
  9.     sum1 = si.keys.inject(0){|sum,item| sum + prefs[person1][item]}  
  10.     sum2 = si.keys.inject(0){|sum,item| sum + prefs[person2][item]}  
  11.       
  12.     sum1Sq = si.keys.inject(0){|sum,item| sum + prefs[person1][item] ** 2}  
  13.     sum2Sq = si.keys.inject(0){|sum,item| sum + prefs[person2][item] ** 2}  
  14.       
  15.     pSum = si.keys.inject(0){|sum,item| sum + prefs[person1][item] * prefs[person2][item]}  
  16.     num = pSum - (sum1 * sum2 / si.size)  
  17.     den = Math.sqrt((sum1Sq - sum1 ** 2 / si.size) * (sum2Sq - sum2 ** 2 / si.size))  
  18.     return (if den == 0 then 0 else num/den end)  
  19. end  

 根据前面的两个相似度的函数,我们可以计算和你相同电影的口味的top N了: 

Ruby代码 复制代码
  1. def top_matches(prefs,person,n=5,similarity="sim_pearson")  
  2.     scores = []  
  3.     #计算相似度  
  4.     prefs.each_key{|other|  scores << eval("[#{similarity}(prefs,person,other),other]")  if other != person}  
  5.     #返回相似读最高的人  
  6.     return scores.sort.reverse[0...n]  
  7. end  

下面我们看看如何推荐你没有看过的电影,我们平时的想法是,如果这部电影 
大家评论很好,我们就认为值得我们看,但是你的口味可能和这些评论很高的 
的人不同,所以和你口味相似的人评论很高的电影,推荐给你效果会很好。 
我们这样虽然一个人对一部电影的评价很高,但是由于他和你的口味不同,那么 
这个评价对于你的贡献也不会太多。结合相似度和评价的一种方法是: 
相似度与评价的成绩作为这个电影评论的一个贡献,同时为了避免评论的人越多 
最终的总分越高,可以用这个公式: 
所有人(相似度与评论分的成绩) 之和 / 相似度之和,于是我们可以得到如下 
代码: 

Ruby代码 复制代码
  1. def get_recommendations(prefs,person,similarity='sim_pearson')  
  2.     totals = {}  
  3.     simSums = {}  
  4.     prefs.each_key do |other|  
  5.         #跳过自己  
  6.         next if person == other  
  7.         sim = eval("#{similarity}(prefs,person,other)")  
  8.         #去掉similarity为0的人  
  9.         next if sim <= 0  
  10.           
  11.         prefs[other].each_key do |item|  
  12.             if (not prefs[person][item]) or (prefs[person][item] == 0) then  
  13.                 #计算相似度和评论的成绩之和  
  14.                 totals[item] = if totals[item] then   
  15.                                   totals[item] + prefs[other][item] * sim   
  16.                                 else   
  17.                                   prefs[other][item] * sim  
  18.                                 end  
  19.                 #相似度之和  
  20.                 simSums[item] = if simSums[item] then  
  21.                                     simSums[item] + sim  
  22.                                 else  
  23.                                     sim  
  24.                                 end  
  25.             end  

抱歉!评论已关闭.