zoukankan      html  css  js  c++  java
  • 集体智慧编程1寻找相近用户

    首先给出一组数据:

    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}}
    怎样寻找相近用户呢,也就是将每个人与其他人进行对比,通过相似度评价值来进行衡量。
    介绍两种相似度评价体系有:欧几里得距离和皮尔逊相关度
    欧几里得距离也就是我们平时学习的距离。
    比如我们对于Toby有'Toby': 'Snakes on a Plane':4.5,'You, Me and Dupree':1.0
    对于LaSalle有:Mick LaSalle':  'Snakes on a Plane': 4.0, 'You, Me and Dupree': 2.0
    这样我们就可以大概计算在两个属性情况下的距离。
    >>> from math import sqrt
    >>> sqrt(pow(4.5-4,2)+pow(1-2,2))
    1.118033988749895

    这样就可以计算出距离,偏好越相似的人,计算出来的距离就越小。另外我们也可以给出倒数,这样偏好越相似的人值就越大,不过考虑到倒数之后可能分母为0,这样在分母上加1,于是有如下:

    >>> 1/(1+sqrt(pow(4.5-4,2)+pow(1-2,2)))
    
    0.4721359549995794

    这样我们给出一个完整的计算相似度的函数:

    # Returns a distance-based similarity score for person1 and person2
    
    def sim_distance(prefs,person1,person2):
    
        si={}
    
        for item in prefs[person1]:
    
            if item in prefs[person2]:
    
                si[item]=1
    
        if len(si)==0: return 0
    
        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+sum_of_squares)
    运行结果:
    >>> import recommendations
    
    >>> recommendations.sim_distance(recommendations.critics,'Lisa Rose','Gene Seymour')
    
    0.14814814814814814
    除了用欧几里得距离之外,我们可以用一个更复杂一点的方法来判断人们兴趣的相似度,用皮尔逊相关系数
    用皮尔逊方法,可以解决一个叫“夸大分值”的情况,就是当一个人的评分总是比较高的时候,可能跟另外一个评分给都的比较低的人有同样的喜好。
    皮尔斯相关系数给出的计算比较特别,我们从下面的过程中看出:
    def sim_pearson(prefs,p1,p2):
    
        si={}
    
        for item in prefs[p1]:
    
            if item in prefs[p2]: si[item]=1
    
        n=len(si)
    
        if n==0: return 0
    
        sum1=sum([prefs[p1][it] for it in si])
    
        sum2=sum([prefs[p2][it] for it in si])
    
        # Sum up 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 up the products
    
        pSum=sum([prefs[p1][it]*prefs[p2][it] for it in si])
    
        # Calculate 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
    运行结果:
    >>> import recommendations
    
    >>> print recommendations.sim_pearson(recommendations.critics,'Lisa Rose','Gene Seymour')
    
    0.396059017191

    上面介绍了两种度量方法,但实际上还有很多其他的方法,比如Jaccard系数或曼哈顿距离。

    现在我们可以对两个人进行比较,那下面我们就可以编写函数根据某个人对其他人进行计算,找到最接近的匹配结果了。

    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]

    n是返回个数,运行

    >>> import recommendations
    
    >>> recommendations.topMatches(recommendations.critics,'Toby',n=3)
    
    [(0.9912407071619299, 'Lisa Rose'), (0.9244734516419049, 'Mick LaSalle'), (0.8934051474415647, 'Claudia Puig')]
    
    这样对于Toby可以参考Lisa Rise所撰写的评论。
    不过我们的目的是为了推荐物品,目前可以找到相近的评论者,不过这个会出现一定的问题,比如对于一些影片还没有做评论,或者有些人对影片随意评价。
    为了解决上述问题,我们对评价值进行加权。
    image
    加权就通过前面算法的相关系数,这样相关性越大,给定的权重也就越大,这样对于一个影片的推荐,我们通过计算所有人的评价值乘以相关系数的和 除以 相关系数的和,如上图total表示所有评价值乘以相关系数的和  sim.sum表示相关系数的和,如果没有评价则不加入。
    上述过程代码如下:
    def getRecommendations(prefs,person,similarity=sim_pearson):
    
      totals={}
    
      simSums={}
    
      for other in prefs:
    
        if other==person: continue
    
        sim=similarity(prefs,person,other)
    
        if sim<=0: continue
    
        for item in prefs[other]:
    
    	    
    
          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
    
      rankings=[(total/simSums[item],item) for item,total in totals.items()]
    
      rankings.sort()
    
      rankings.reverse()
    
      return rankings

    运行结果:

    >>> import recommendations
    
    >>> recommendations.getRecommendations(recommendations.critics,'Toby')
    
    [(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
    这样我们看了一下匹配结果:
    >>> import recommendations
    
    >>> movies=recommendations.transformPrefs(recommendations.critics)
    
    >>> recommendations.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')]
    而且根据匹配结果也可以看到相关评论人。
    >>> recommendations.getRecommendations(movies,'Just My Luck')
    [(4.0, 'Michael Phillips'), (3.0, 'Jack Matthews')]

     

    下面就给出了一个真实的案例 构建一个基于del.icio.us的链接推荐系统

  • 相关阅读:
    开源权限框架shiro 入门
    Struts1.2入门笔记
    memcache概述
    教你如何将中文转换成全拼
    WPF第一章(XAML前台标记语言(Chapter02代码讲解))
    WPF第一章(XAML前台标记语言)
    WPF简介
    Activity以singleTask模式启动,intent传值的解决办法
    linux下查看文件编码以及编码转换
    Fedora 17字体美化
  • 原文地址:https://www.cnblogs.com/fengbing/p/3600242.html
Copyright © 2011-2022 走看看