Mengdong的技术博客

学习,记录,分享

导航

《集体智慧编程》第2章:推荐

本书读书笔记目录:http://www.cnblogs.com/mdyang/archive/2011/07/07/PCI-contents.html

第2章 推荐

想得到电影推荐的时候怎么做?最原始的做法就是问自己的朋友。一开始,你会要求大多数朋友给你推荐电影,经过一段时间,你发现有些朋友比别人”有眼光“。这实际上意味着相对于别人,这些朋友与你具有更高的偏好相似度,因此他们喜欢的电影你很可能也会喜欢。这样一来,你自然就会更关注那些他们看过觉得不错,而你还没有看过的电影。

这种就是众多协同过滤(collaborative filtering)技术的来源。

收集评价信息

本章构建一个电影推荐程序,程序基于几个用户对几部电影的评分进行推荐。评分数据采用嵌套字典(Python)的形式给出,如下所示:

评分数据的格式是{人:评分表},其中评分表的格式是{电影名:评分}. 因此评分表记录了各人对其看过的若干部电影的评分(位于区间[1,5]中的数)。

寻找相似的人

本节用两种不同指标分别计算人与人之间的相似度:欧氏距(Euclidean Distance)与皮尔逊相关系数(Pearson Correlation)。

欧氏距(Euclidean Distance)

欧氏距利用类似欧氏几何空间内两点间距离公式记录两个项目的“相似度(距离越近越相似)”。以Snakes和Dupree两部电影为例,我们可以构建如下的用户二维空间分布(横轴为Dupree电影评分,纵轴为Snakes电影评分):

Toby(1,4.5)与LaSalle(2,4)之间的欧氏距离就可以表示为:

dE=sqrt(pow(1-2,2)+pow(4.5-4,2)) 

显然dE≥0. 通过加1后求倒数,可以把距离转换为相似度:

sE=1/(dE+1). 显然有0<sE≤1.  

由此可以使用欧氏距离计算出每两个用户之间的sE值。sE越大,两人越相似。

皮尔逊相关系数(Pearson Coefficient)

Wikipedia上关于皮尔逊相关系数的定义:http://en.wikipedia.org/wiki/Pearson_coefficient

简单地说,皮尔逊相关系数衡量的是两个人的分布点在多大程度上能够拟合到一条直线上。

优点是它能够处理未经规格化的数据,比如某一阶段用户给出的的评分比往常要低(可能是这个阶段的电影都比较烂),并不影响皮尔逊相关系数的准确。

给出两个皮尔逊相关系数的例子,左图中Gene Seymour和Mick LaSalle的点较为分散,距离最佳拟合直线都比较远,且对于每部电影的评分都有较大差距,因此其相关系数较低(约0.4);而右图中Jack Matthews和Lisa Rose的点距离最佳拟合直线都较近,且对每部电影的评分都较为接近,因此具有更高的相关度(约0.75)。

可用如下公式计算两个项目A(a1,a2...an)与B(b1,b2...bn)的皮尔逊相关系数(为了节省篇幅使用这个公式。本公式根据书中给出的Python代码抽象而来。根据wiki的解释,这个算法实际只是一个皮尔逊相关系数的近似算法,真正的皮尔逊系数计算起来很复杂,因此用一个简化的近似算法替代):

sP是一个位于[-1,1]之间的数,当AB中每个对应子项目都相同时sP=1,代表AB之间具有最大相似度。 

其他相似度指标

除了以上两个方法,还有很多其他可用来衡量相似度的指标:

  1. Jaccard系数(Jaccard Coefficient,亦称为Tanimoto Coefficient,即谷本系数)http://en.wikipedia.org/wiki/Jaccard_coefficient
  2. 曼哈顿距离(Manhattan Distance)http://en.wikipedia.org/wiki/Manhattan_distance
  3. 马氏距离(Mahalanobis Distance)http://en.wikipedia.org/wiki/Mahalanobis_distance
  4. 更多可见 http://en.wikipedia.org/wiki/Metric_(mathematics)#Examples

具体用哪个要看应用需要。

推荐电影

计算出每两人之间的相似度,就可以对某个人p对应的相似度列表排序,从而得出与p最相似的前n个人(n可变)。p可以通过查看这些人的评分决定看什么电影。

再进一步,能不能不用看评分,而直接对p推荐电影呢?答案是肯定的。一种做法是:

  1. 按照相似度选出与p最相似的前n个人
  2. 以相似度作为权值计算每部电影相对于p的综合评价
  3. 选出评价最高的电影推荐给p

用一个直观的例子说明如下(取p=Toby, n=5)

表中给出了5个用户(Rose, Seymour, Puig, LaSalle, Matthews)对于Toby还没看的3部电影(Night, Lady, Luck)的评分。对于每部电影,先计算加权(权值即为相似度)后的评分和T(表中Total),根据T/SS为相似度的加和)的值推荐电影(推荐得分最高的)。使用T/S而不是T的目的是为了进行一般化,因为在实际的数据中,不同电影给出评分的用户数量是不一样多的。如果不除以相似度和,那么评分用户多的电影计算出的T值也高,而除以S后所有电影无论评分用户多少,T/S都能够一致映射到[1,5]的区间内。

基于项目的过滤

例子:打开Amazon里《Programming Python》一书的购买页面,下方会推荐如下几本书:

《Learning Python》

《Python Cookbook》

《Python in a Nutshell》

《Python Essential Reference》

……

前面的推荐程序需要反复遍历整个数据集才能计算出排名信息(对每个用户计算他与所有其他用户的相似度,O(n2)复杂度)。这对于只有几千个用户/数据的系统还可以应用,但对于像Amazon这样动辄成百万上亿的数据量来说,这样的算法十分低效。而且在Amazon这种大型在线商城中,由于用户之间差异性较大,计算每两个用户之间的相似度并不实用(例如a只买书,而b只买数码产品,ab之间没有交集)。

前面用到的协同过滤技术称为基于用户的协同过滤(user-based collaborative filtering)。与之对应的另一种技术称为基于项目的协同过滤(item-based collaborative filtering)。这种技术更适用于大数据集的处理。具体为什么,看过下面的计算步骤就知道了。

计算步骤

1) 构建数据

基于项目过滤的计算过程这一步与前面基于用户过滤类似,只是数据的组织方式由以人为单位组织转为以产品为单位组织。以电影的例子为例,只需要将下图所示的数据

调整为

即可。

2) 计算相似度

计算相似度的具体方法相同(欧氏距/皮尔逊相关度),但是计算的范围不同了,从计算两两用户间的相似度变为计算两两项目间的相似度。

3) 推荐(主要区别)

假设现在需要对一个人p推荐电影,那么对于每一部p看过的电影mw,查找算每一部p没看过的电影mumw的相似度(这个相似度在2)已经算出来了),以这个相似度为权值,根据对p对已看过电影的评分,计算p对未看过电影的可能评分值。

用一个例子说明如下(p=Toby, mw={Snakes, Superman, Dupree}, mu={Night, Lady, Luck}):

T/S代表Toby对每部没看过电影的可能评分,在全部3部Toby没看过的电影里,Night取得了最高的可能评分,因此系统推荐Toby接下来看Night.  

基于项目方案的优势

  1. 大型应用中(例如Amazon)项目的数量往往远远少于用户数量,因此基于项目的方案2)步的计算量较小。
  2. 由于2)的结果可以复用(至少可以不用每次都重新计算,可以阶段性更新,例如几天计算一次),因此计算开销主要在3)这一步。从上面的计算步骤可以看出,基于项目的方案在3)时只需要读取Toby一人的用户数据,而不像基于用户的方案在3)时需要遍历多个用户的评分数据。

构建一个基于del.icio.us的链接推荐程序

(用到的思路和上面是一样的,只不过用了del.icio.us的Open API与pydelicious库,不在此赘述。有兴趣的朋友可自行找书练习)

基于用户还是基于项目?

根据情况。

基于用户:

  1. 需要“推荐用户”功能时
  2. 实现较为简单,适合数据集不大时用

基于项目:

  1. 需要基于项目推荐
  2. 数据集很大

posted on 2011-07-09 10:39  mdyang  阅读(1594)  评论(1编辑  收藏  举报