集体智慧编程学习笔记(2.2)提供推荐

第二章 提供推荐


(六) 为评论者打分 Ranking the Critics


既然我们已经有了对两个人进行比较的函数,下面就可以编写函数,根据指定人员对每个人进行打分,并找出最接近匹配项的结果。在本例中 ,我们对寻找与自己有相似品味的影评者很感兴趣,因为这样我们就可以知道在选择影片时应该采纳谁的建议了。将该函数加入 recommendations.py 中,以得到一个人员的有序列表,这些人与某个指定人员具有相近的品味:

#从反映偏好的字典中返回最为匹配者
#返回结果的个数和相似度函数均为可选参数
#scores是一个二元列表,元素为(相似度评价值,与person比较的人)
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]
对列表排序也可写为如下代码:

#对列表进行排序,评价者最高的排在最前面
    scores.sort(reverse=True)
    return scores[0:n]
该函数利用了Python的列表解析,采用先前定义过的某种距离度量算法,将自身和字典中的其他每一位用户都进行了比较,然后,函数返回排序结果中的前n项。


调用该方法并传入自己的姓名,将得到一个有关影评者及其相似度评价值的列表:

import recommendations
from imp import reload
reload(recommendations)
recommendations.topMatches(recommendations.critics,'Toby',n=3)

结果如下:

[(0.9912407071619299, 'Lisa Rose'),
 (0.9244734516419049, 'Mick LaSalle'),
 (0.8934051474415647, 'Claudia Puig')]

根据返回的结果我们了解到,应该阅读 Lisa Rose 的所撰写的评论,因为她的品味与我们很相近。


(七) 推荐物品 Recommending Ltems


找到一位趣味相投的影评者并阅读他所撰写的评论固然不错,但现在我们真正想要的不是这些,而是一份影片的推荐。当然,我们也可以查找与自己品味最为相近的人,并从他所喜欢的影片中找出一份自己还未看过的影片,不过这样做太随意了(permissive)。有时,这种方法可能出现问题:评论者还未对这些影片进行评论,而这些影片也许就是我们喜欢的。还有一种情况是,我们会找到一个热衷某部影片的古怪评论者,而根据 topMatches 所返回的结果,所有其他的评论者都不看好这部影片。

为了解决上述问题,我们须通过一个经过加权的评价值来为影片打分,评论者的评分结果因此形成了先后的排名。为此,我们需要取得所有其他评论者的评价结果,借此得到相似度后,再乘以他们为每部影片所给的评价值。表2-2给出了这一方法的执行过程:


                                                                                                                                表2-2 为Toby提供推荐

表中列出了每位评论者的相关度评价值,以及他们对三部影片《The Night Listener》、《Lady in the Water》和《Just My Luck》的评分情况(我们还不曾参与评分)。以S.x开头的列给出了乘以评价值后的相似度。如此一来,相比于与我们不相近的人,那些与我们相近的人将会对整体评价值拥有更多的贡献。总计一行给出了所有加权评价值的总和。
我们也可以选择利用总计值来计算排名,但我们还必须考虑到,一部受更多人评论的影片会对结果产生更大的影响。为了修正这一问题,我们需要出了表中名为Sim.Sum的那一行,它代表了所有对这部影片有过评论的评论者的相似度之和。由于每个人都对影片《The Night Listener》进行了评论,因此我们用总计值除以全部相似度之和。而对于影片《Lady in the Water》而言,Puig并未做过评论,因此我们将这部影片的总计值除以所有其他人的相似度之和。表中最后一行给出了相除结果。

下列代码反映了上述过程,它对欧几里德距离评价或是皮尔逊相关度评价都是使用的,将其加入 recommendations.py 中:

#利用所有他人评价值的加权平均,为某人提供建议
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:
            #如果在自己对应的字典prefs中没有需查询的影片,或者自己的评分为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

上述代码循环遍历所有位于字典prefs中的其他人。针对每一次循环,它会计算有person参数所指定的人员与这些人的相似度,然后遍历所有打过分的项。

totals[item]+=prefs[other][item]*sim 说明了每一项的最终评价值的计算方法-----用每一项的评价值乘以相似度,并将所有的乘积累加起来,最后,将每个总计值除以相似度之和,借此对评价值进行归一化处理,然后返回一个经过排序的结果。

接下来找自己应该要看的电影:

recommendations.getRecommendations(recommendations.critics,'Toby')
结果:
[(3.0, 'The Nighr Listener'),
 (3.0, 'Lady in the Water'),
 (1.5, 'Just My Luck')]

recommendations.getRecommendations(recommendations.critics,'Toby',similarity=recommendations.sim_distance)#改用欧几里得距离评价为Topy推荐电影

结果:

[(3.0, 'The Nighr Listener'),
 (3.0, 'Lady in the Water'),
 (1.5, 'Just My Luck')]
此处,我们不仅得到了一个经过排名的影片列表,还推测出了自己对每一部影片的评价情况。根据这份结果,我们可以决定自己究竟要不要观看其中的某部影片,还是干脆什么也不看。有赖于具体的应用,假如无法满足某一用户给出的标准,我们也可以决定不给于建议。选择不同的相似性度量方法,对结果的影响是微乎其微的。

现在我们已经建立起了一个完整的的推荐系统,它适用于任何类型的商品或网络链接。我们要做的全部事情就是:建立一个涉及人员、物品和评价值的字典,然后就可以借此来为任何人提供建议了。在本章的后续章节,我们将会利用 del.icio.us.API 来获取真实数据,进而向人们推荐 Web 站点。

注:setdefault()函数

Python 字典 setdefault() 函数和get() 方法类似, 如果键不存在于字典中,将会添加键并将值设为默认值。

setdefault()方法语法:    dict.setdefault(key, default=None)

参数:     key -- 查找的键值。
              default -- 键不存在时,设置的默认键值。
返回值:   如果字典中包含有给定键,则返回该键对应的值,否则返回为该键设置的值。

eg:

dict={'key': 'a'}
dict.setdefault('key0', 'b') # 键key0不存在,故插入此键,并以b为键值.
dict

结果:{'key0': 'b', 'key': 'a'}

(八) 匹配商品 Matching Products


现在,我们已经知道了如何为指定人员寻找品味相近者,以及如何向其推荐商品的方法,但是假如我们想要了解哪些商品是彼此近似的,又该如何做呢?也许我们曾经在购物网站上遇到过这种情形,尤其是网站还没有收集到关于用户的足够信息时。图2-4显示了 Amazon 网站上有关《Programming Collective Intelligence》一书的局部网页。



      
                                                                          图2-4 Amazon 网站列出了与《 Programming Collective Intelligence 》相近的同类商品

在这种情况下,我们可以通过查看哪些人喜欢某一特定商品,以及这些人喜欢哪些其他物品来决定相似度。事实上,这和我们此前用来决定人与人之间相似度的方法是一样的------只需要将人员与物品兑换即可。因此,假如我们将


  
  
{'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 Nighr Listener':3.0,'You,Me and Dupree':3.5}}

换成
{'Lady in the Water':{'Lisa Rose':2.5,'Gene Seymour':3.0},
 'Snakes on a Plane':{'Lisa Rose':3.5,'Gene Seymour':3.5},
 'Just My Luck':{'Lisa Rose':3.0,'Gene Seymour':1.5},
 'Superman Returns':{'Lisa Rose':3.5,'Gene Seymour':5.0},
 'You,Me and Dupree':{'Lisa Rose':2.5,'Gene Seymour':3.5},
 'The Night Listener':{'Lisa Rose':3.0,'Gene Seymour':3.0}} etc..
就可以复用以前所写的方法了。将执行这一转换过程的函数加入 recommendations.py 中:
#转换函数
def transformPrefs(prefs):
    result={}
    for person in prefs:
        for item in prefs[person]:
            result.setdefault(item,{})

            #将物品与人员对调
            result[item][person]=prefs[person][item]
    return result
        
现在,调用 topMatches 函数,得到一组与《Superman Returns》最为相近的影片:
reload(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.09759000729485331, 'The Night Listener'),
 (-0.42289003161103106, 'Just My Luck')]
注意:在本例中,实际存在一些相关评价值为负例的情况,这表明那些喜欢影片《Superman Returns》的人,存在不喜欢《Just My Luck》的倾向。

上面我们示范了为某部影片提供相关影片的推荐,不仅如此,我们甚至还可以为影片推荐评论者。例如,也许我们正在考虑邀请谁和自己一起参加某部影片的首映式。

recommendations.getRecommendations(movies,'Just My Luck')

结果:   [(3.0, 'Jack Matthews')

将人和物进行对调并不总是能得到有价值的结果,但是在大多数情况下,这将有助于我们做出有意义的对比。为了向不同的个体推荐商品,在线零售商可能会收集人们的购买历史。将商品和人进行对调------正如我们此前所做的那样------可以令零售商找到购买某些商品的潜在客户,这可能对他们为了清仓处理某些商品而在市场营销投入方面制定的规划很有帮助。这种做法的另一个潜在用途是,在专门推荐链接的网站上,这样做可以确保新出现的链接,能够被那些最有可能对它产生兴趣的网站用户找到。


图2-5 《Superman Returns》和《Just My Luck》存在负相关性


(九) 构建一个基于del.icio.us的链接推荐系统 Building a del.icio.us Link Recommender

现在学习如何从最受欢迎的在线书签网站上获取数据,如何利用这些数据查找相近用户,并向他们推荐以前未曾看过的链接。该网站------可以通过http://del.icio.us 访问到,允许人们建立自己的账号,并允许张贴自己感兴趣的链接,以备日后参考。我们可以访问网站并查看其他人张贴的链接,也可以浏览许多不同用户所张贴的热门链接。图2-6展示了一个取自 el.icio.us 网站的网页样例。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值