推荐系统初探之一 —— 寻找相似的用户

来源:互联网 发布:python 微信告警 编辑:程序博客网 时间:2024/05/22 16:40

不知当你登陆亚马逊、淘宝等购物网站时,是否留意过那神奇推荐栏:当你买过一部手机,那里会出现你需要的手机配件;但你买过一本书,它会给你推荐一大堆类似的书籍;而有时候它甚至会向你推荐你可能喜欢的影片,即使你可能只在这买过食品……

        其实,大多数购物网站都会有一个推荐系统,通过分析你的兴趣偏好,找到与你有相同品味的人,以此来把你可能喜欢的商品推荐给你。

        想知道这些推荐系统背后的秘密吗?现在开始,让我们使用python语言,揭开这些推荐系统背后的秘密。

 一、数据的引入

        首先,我们建一个名为recommendations.py的python文件,用一段代码建立一组简单的数据,内容为几位影评者对不同电影的评价

Python代码  收藏代码
  1. # -*- coding: cp936 -*-  
  2. #一个涉及影评者机器对几部电影评分情况的字典  
  3. critics = {'Lisa Rose':{'Lady in the Water':2.5'Snacks on a Plane': 3.5,  
  4.                         'Lust My Luck': 3.0'Superman Returns': 3.5,  
  5.                         'You, Me and Dupree': 2.5'The Night Listener': 3.0},  
  6.            'Gene Seymour':{'Lady in the Water':3.0'Snacks on a Plane': 3.5,  
  7.                         'Lust My Luck': 1.5'Superman Returns': 5.0,  
  8.                         'You, Me and Dupree': 3.5'The Night Listener': 3.0},  
  9.            'Michael Phillips':{'Lady in the Water':2.5'Snacks on a Plane': 3.0,  
  10.                         'Superman Returns': 3.5'The Night Listener': 4.0},  
  11.            'Claudia Puig':{'Snacks on a Plane': 3.5'Lust My Luck': 3.0,  
  12.                            'Superman Returns': 4.0'You, Me and Dupree': 2.5,  
  13.                            'The Night Listener': 4.5},  
  14.            'Mick LaSalle':{'Lady in the Water':3.0'Snacks on a Plane': 4.0,  
  15.                         'Lust My Luck': 2.0'Superman Returns': 3.0,  
  16.                         'You, Me and Dupree': 2.0'The Night Listener': 3.0},  
  17.            'Jack Matthews':{'Lady in the Water':3.0'Snacks on a Plane': 4.0,  
  18.                             'Superman Returns': 5.0'You, Me and Dupree': 3.5,  
  19.                             'The Night Listener': 3.0},  
  20.            'Toby':{'Snacks on a Plane': 4.5'Superman Returns': 4.0,  
  21.                    'You, Me and Dupree': 1.0}}  

       在这些数据中,通过1—5的评分来表示评价者对某影片的喜欢程度。而我们要做的,就是从这些评分中挖掘出不同用户的兴趣偏好,以此为依据进行推荐。

       好了,有了数据,我们就可以开始工作了!

 

二、寻找相近的用户

       接下来我们要做的,是找一种方法来确定人们的品味。品味是一个抽象的东西,没法衡量,但是可以比较。所以我们引入一个新的概念——相似度评价值,用以衡量不同人的品味相似度。为计算相似度评价值,我们在此继续引入两个概念:欧几里得距离皮尔逊相关度

       〈1〉欧几里得距离评价

       顾名思义,这是欧几里得最先提出的概念。这位古希腊几何大神的研究成果曾一度伴随着我们的成长,我们现在讨论的他老人家的成果,实质上是两点间距离公式向N维空间的类比拓展。

      

我们知道:

在一维空间(即直线)中两点的距离为 

二维空间中的距离为

三维空间中的距离则为……

 

以此类推,可以认为N维空间中两点距离仍旧符合以上规律 ,由N组参数差的平方和开平方跟来表示,这种形式表示的距离就叫欧几里得距离。

好了,现在让我们回归正题。了解了欧几里得距离的概念,我们就可以用它来构建我们的相似度评价值体系了。



 

      如图2—1所示,若将电影 'Snacks on a Plane' 与 'You, Me and Dupree' 的评分作为坐标轴的参数,则用户可以用二维空间中的点来表示,其坐标为各自的对应坐标轴电影的评分值,在此只给出了两个参数,如果用上所有六部电影的评分,可构成一个六维空间(靠自己想象了),那么该空间中两名用户(即两点)间的欧几里得距离越短,表示这两位用户的品味越相近。利用数据,我们可以很轻易得出所有用户之间的欧几里得距离,由此得到相似度——不过在这之前似乎还有个问题:我们希望评价的函数使得偏好越相近的用户得到的相似度函数值越高,而欧几里得距离结果却恰好与此相反。为此,我们采用对函数值+1(防止被零除的情况发生),然后取倒数的方法,使得函数返回0到1之间的值,数值越大表示相似度越高,其中1代表两个人品味完全相同。向recommendations.py中添加以下代码,构建欧几里得函数:

 

Python代码  收藏代码
  1. from math import sqrt  
  2.   
  3. #返回一个关于person1与person2基于欧几里得距离的相似度评价  
  4. def sim_distance(prefs, person1, person2):  
  5.     #得到两个人都看过的电影的列表  
  6.     shared_moives = {}  
  7.     for moive in prefs[person1]:  
  8.         if moive in prefs[person2]:  
  9.             #两个人都看过的影片设为1  
  10.             shared_moives[moive] = 1  
  11.       
  12.     #如果两人没有都看过的电影,函数返回0  
  13.     if len(shared_moives) == 0:  
  14.         return 0  
  15.     #求所有差值平方和,算出相似度  
  16.     sum_of_squares = sum([pow(prefs[person1][moive] - prefs[person2][moive],2)  
  17.                           for moive in prefs[person1] if moive in shared_moives])  
  18.     sim = 1/(sqrt(sum_of_squares)+1)  
  19.     return sim  

 

 

      现在我们可以调用这个函数,通过输入两个人名,来得到两人基于欧几里得距离的相似度评价值。在解释器中执行如下测试命令:

 

Python代码  收藏代码
  1. >>> reload(recommendations)  
  2. >>> sim_distance(recommendations.critics,'Lisa Rose''Gene Seymour')  
  3. 0.29429805508554946  

     用这种方法可以得到任意两个人之间的相似度评价。

 

     〈2〉皮尔逊相关度评价

 

      前面我们了解了基于欧几里得距离的评价方法,现在我再介绍一种更复杂的方法——基于皮尔逊相关系数的评价方法。皮尔逊相关系数,听起来很NB,但仔细一看不过就是我们高中数学学过的相关系数,即用最小二乘法解决线性回归问题时用到的参数。当然,高中老师从未向我们解释过这个公式的含义,再此我们不妨自行研究一下。

 

      这是高中课本上关于二维空间散点集的皮尔逊相关系数公式,表示两组数据之间的相关程度,取值为-1至1之间,其中+1/-1表示两组数据完全分布在一条上,1表示呈正相关,-1表示呈负相关。

        事实上,皮尔逊相关系数又称为皮尔逊积矩相关系数,我们可以试着从几何角度理解它:
       对于一组n个数据(xi,yi)(i = 1,2,3……n),我们可以用两个坐标轴的所有数据数据分别生成n维向量(如X =(x1,x2……xn),Y =(y1,y2……yn)),两个向量的夹角余弦值即为皮尔逊相关度。只是注意在该算法中要对数据进行中心化,即将向量的每一维根据均值进行平移,形成以样本中心为原点的向量。

        设样本中心(x0, y0)则向量 X = [ (x1-x0), (x2-x0)……,(xn-x0)],Y = [ (y1-y0), (y2-y0)……(yn-y0)]。


                    

再经过一些代数变换即可得到上面左边的式子,即我们接下来计算时要用到的式子。
 

        类似的,我们选取两位用户的评分值为两坐标轴,可以将所有的电影映射为二维平面上的点,得到图2-2



 

        通过我们中学学过的最小二乘法求线性回归直线的公式,我们也很容易找到一条“最佳拟合直线”。可以想象,如果两位用户品味完全相同,那么他们对所有电影的评分都会相同,我们将得到一条斜率为1的过原点的直线。图2-2中的皮尔逊相关系数约为0.4,而图2-3则展示了一个相关度更高的例子,约为0.75。

 

 

       在采用皮尔逊方法进行评价时,我们还能发现一点,就是它可以修正评分者评分习惯对结果的影响。举个例子,2-3中,Jack对每部电影的评分都明显高于Lisa:我们可以认为Jack很慷慨,习惯打高分;而
Lisa比较吝啬,喜欢打低分。不过在皮尔逊相关度的计算中,这并不是问题,因为虽然两人的评分习惯不同,但大体的相关性还是显而易见的。然而,在欧几里得距离的计算中,结果就完全不同了——实际结果中两人的欧几里得距离会很大,因为他们在每一维中都有很大的分差,即使他们的品味是那么相似。因此,在这个场景中,皮尔逊方法显然更合适。

       逊相关度评价的算法函数如下:

Python代码  收藏代码
  1. #返回person1与person2的皮尔逊相关度  
  2. def sim_pearson(prefs, person1, person2):  
  3.     #得到两个人都看过的电影的列表  
  4.     shared_moives = {}  
  5.     for moive in prefs[person1]:  
  6.         if moive in prefs[person2]:  
  7.             #两个人都看过的影片设为1  
  8.             shared_moives[moive] = 1  
  9.       
  10.     #如果两人没有都看过的电影,函数返回1  
  11.     if len(shared_moives) == 0:  
  12.         return 1   #这里到底应该取几我持保留意见  
  13.     #对所有偏好求和  
  14.     sum1 = sum(prefs[person1][moive] for moive in shared_moives)  
  15.     sum2 = sum(prefs[person2][moive] for moive in shared_moives)  
  16.   
  17.     #求平方和  
  18.     sum1Sq = sum([pow(prefs[person1][moive],2for moive in shared_moives])  
  19.     sum2Sq = sum([pow(prefs[person2][moive],2for moive in shared_moives])  
  20.   
  21.     #求乘积之和  
  22.     pSum = sum([prefs[person1][moive] * prefs[person2][moive]  
  23.                 for moive in shared_moives])  
  24.   
  25.     #计算皮尔逊评价值  
  26.     n = len(shared_moives)  
  27.     num = pSum - (sum1 * sum2 / n)  
  28.     den = sqrt((sum1Sq - pow(sum1,2) / n) * (sum2Sq - pow(sum2,2) / n))  
  29.     if den == 0 :return 0  
  30.     r = num / den  
  31.     return r  

  我们可以采用类似的方式在解释器中运行代码测试:

 

Python代码  收藏代码
  1. >>> reload(recommendations)  
  2. >>> sim_pearson(recommendations.critics, 'Lisa Rose''Gene Seymour')  
  3. 0.39605901719066977  

 

       至此,我们已经掌握了相似度评价的两大神器——欧几里得距离皮尔逊相关度,怎么样?是不是没有想象中的那么难?嘿嘿,不要走开,后面的内容更精彩,下篇博客,我们将走进真正的机器推荐系统,向 Toby 推荐电影,请君拭目以待吧!



http://t1174779123.iteye.com/blog/1956798

0 0
原创粉丝点击