推荐系统初探之二 —— 推荐方法
在上一篇文章中,我们了解到了两种相似度评价方法:欧几里得距离和皮尔逊相关度方法,其实
类似功能的算法好多,比如Jaccard系数和曼哈顿距离算法等。有兴趣的同学可以登陆http://en.wikipedia.org/wiki/Metric_%28mathematics%29#Examples ,你可以找到并学习更多用于比较的度量算法,在此不展开。下面我们开始进入下一步:为推荐者打分。
四、为推荐者打分
既然我们已经有了一个对两个人进行评价的方法,那么只要循环调用这个方法,我们就可以很容易的得到所有用户之间的相似度。用与某个用户品味相近的用户的评价为参考,就可以大致推测出该用户对该商品的评分,以此为依据,就可以对指定用户进行推荐。
据此思路,我们在recommendations.py中添加topMatchs方法,具体代码如下:
#寻找字典中匹配度较高的人并排序 def topMatchs(prefs, person, n = 5, similarity = sim_pearson): scores = [(similarity(prefs, person, other), other) for other in prefs if other != person] #对scores列表进行排序,评价值最高的在前面 scores.sort() scores.reverse() return scores[0:n]
注意这个方法的参数,其中n为所要返回的数据个数,默认为5,另外需要一个函数指针similarity,用来指定计算相似度的方法名称,在这里我们可以指定我们前面写好的两种方法中的任一个,sim_distance或sim_pearson
运行测试语句:
>>> reload(recommendations) >>> print topMatchs(recommendations.critics, 'Toby', 3) [(0.9912407071619299, 'Lisa Rose'), (0.9244734516419049, 'Mick LaSalle'), (0.8934051474415647, 'Claudia Puig')] >>> print topMatchs(recommendations.critics, 'Lisa Rose', 5) [(0.9912407071619299, 'Toby'), (0.7470178808339965, 'Jack Matthews'), (0.5940885257860044, 'Mick LaSalle'), (0.5669467095138396, 'Claudia Puig'), (0.40451991747794525, 'Michael Phillips')] >>> print topMatchs(recommendations.critics, 'Lisa Rose', 5, sim_distance) [(0.4721359549995794, 'Michael Phillips'), (0.4142135623730951, 'Mick LaSalle'), (0.38742588672279304, 'Claudia Puig'), (0.3483314773547883, 'Toby'), (0.3405424265831667, 'Jack Matthews')]
这里有必要关注的是'Lisa Rose'的运行结果,正像我之前提到的,这里两种相似度计算方法的结果天差地别,比如我之前提到的'Lisa Rose'与'Jack Matthews'的问题,二者在皮尔逊算法中品味确实很相似,但到了欧几里得算法中则显得品味相差很大,所以在本情境中显然还是用皮尔逊算法合理些。
有了topMatchs函数,我们已经可以很轻易地知道谁与我们的品味更相近,通过查看他们的影评分数,我们就可以参考他们看过的哪些电影中那些我可能会喜欢,有兴趣的读者也不妨把自己的评分加到字典中,试着看看谁与你的品味更相似。
五、基于评价者的推荐
找到与自己兴趣相投的用户并从他们那找到适合自己看的电影固然很好,但其实我们真正想要的是一份对于所有影片的推荐,那样就省得从一堆评论中寻找了有用信息了。
为了解决这个问题,我们用一个简单的加权算法来给影片打分:将所有其他评论者的评分分别乘上他们与用户相似度然后取平均值。这样,相比于与我们品味不相近的人,与我们品味相似的人的评分对最终结果的贡献显然更高,结果也就通常更可信。不过这里要注意一点,由于是根据相似度进行取平均,所以除数不是其他评论者的个数,而是所有其他评论者与我们相似度的和!对于加权算法,这点并不难理解。
我们将所有其他用户的评分及其与Toby的相似度列表如下:
其中Night、Lady、Luck列为他们对对应电影的评分,S.x Xxxx列代表他们评分按相似度的加权值及与相似度的乘积,而sim.sum一行则代表所有相似度之和,最后一行的总计/Sim.Sum则代表最终结果。
于是,我们继续在文件中建立getRecommendations函数来重复上一过程,代码如下 :
#利用所有其他人评价的加权平均,为某人提供建议 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 moive in prefs[other]: #只对自己没有看过的影片做评价 if moive not in prefs[person] or prefs[person][moive] == 0: #计算相似度*评价值之和 totals.setdefault(moive, 0) totals[moive] += prefs[other][moive]*sim #计算相似度之和 simSums.setdefault(moive, 0) simSums[moive] += sim #建立一个归一化的列表 rankings = [(total / simSums[moive], moive) for moive,total in totals.items()] #排序 rankings.sort()#升序排列 rankings.reverse()#颠倒(降序排列) return rankings
该函数循环遍历perfs中所有的其他人,每一轮循环中,他都会算出其他人与person的相似度,然后找出所有person没看过的电影,分别计算每部电影相似度*评价值之和与相似度之和,最后做商得出结果,返回一个列出所有person没看过的电影与对应评分的列表。
接下来,我们就可以为Toby推荐电影了:
>>> recommendations.getRecommendations(recommendations.critics, 'Toby') [(3.3477895267131013, 'The Night Listener'), (2.8325499182641614, 'Lady in the Water'), (2.5309807037655645, 'Lust My Luck')] >>> recommendations.getRecommendations(recommendations.critics, 'Toby', sim_distance) [(3.457128694491423, 'The Night Listener'), (2.778584003814924, 'Lady in the Water'), (2.4224820423619167, 'Lust My Luck')] >>>
怎么样?庆祝一下吧,我们已经成了半个电影推荐专家了,现在我们可以建议Toby今晚去看'The Night Listener',当然,选择权还是在Toby自己。而且不知道你们注意到没有,尽管在前面讨论欧几里得算法有其缺陷,但是具体采取哪种方法对于最终的结果并没有太大影响。
现在,基于推荐者的推荐方法我们已经掌握的差不多了。其实没什么难的,我们做的全部工作不过是:1、建立一个涉及人员、物品和评价的字典 2、然后借此来为任何人提供建议。只要有数据,一切似乎都不是问题。
但是,富有经验的程序员马上会提出质疑,咱们这个程序效率太低下了!
这种方法对于一个小型的应用完全是没有问题的,但如果是类似于豆瓣淘宝这种动辄几千万用户的应用来说,将一个用户和其他所有用户进行比较,然后再对每位用户评分过的商品进行比较,你会发现我们的系统已经不给力了。
因此,我们不得不继续讨论另一种在大数据条件下表现更好的方法。
五、基于物品的推荐
现在我们已经十分熟悉如何为指定人员寻找品味相近者,以及如何向其推荐商品的方法。但是,假如我们想了解那些物品是相近的呢?也许我们在网上购物时就曾遇到过这个问题,特别是当购物网站刚起步,还没收集到的足够的用户数据的时候。事实上,像亚马逊一些购物网站也是可以自动为我们列出相近的物品的。那么,在这背后的又是哪些算法呢?
事实上,我们可以通过查看哪些人喜欢某一物品,以及这些人喜欢哪些其他物品来确定物品间的相似度。而如果你想得足够清楚的话,就会发现这与确定人之间的相似度其实是一样的——只需要把字典中的人与物品对调位置。即:
把 {'Lisa Rose':{'Lady in the Water':2.5, 'Snacks on a Plane': 3.5,
'Lust My Luck': 3.0, 'Superman Returns': 3.5……
换成{'Lady in the Water':{'Lisa Rose':2.5, 'Gene Seymour':3.0},
'Snake on a Plane':{'Lisa Rose':3.5, 'Gene Seymour':3.5……
我们就可以利用前面已经写好的方法对所有物品彼此间的相似度进行计算了。
继续将转换函数写入recommendations.py中:
#将数据转换的方法 def transprefs(prefs): result = {} for person in prefs: for moive in prefs[person]: #将电影和评论人对调 result.setdefault(moive, {}) #将物品与人对换 result[moive][person] = prefs[person][moive] return result
试着调用topMatchs方法,我们可以与Superman Returns最相近的电影:
>>> moives = recommendations.transprefs(recommendations.critics) >>> recommendations.topMatchs(moives, 'Superman Returns') [(0.6579516949597695, 'You, Me and Dupree'), (0.4879500364742689, 'Lady in the Water'), (0.11180339887498941, 'Snacks on a Plane'), (-0.1798471947990544, 'The Night Listener'), (-0.42289003161103106, 'Lust My Luck')]
在这里注意,由于皮尔逊相关度的特性,出现了一些相似度为负值的情况,这意味着喜欢'Superman Returns'的人存在着不喜欢'Lust My Luck'的倾向!(意外发现吧)
同样的,和为评价人推荐电影一样,我们可以为某部电影推荐评论人:
recommendations.getRecommendations(moives,'Lust My Luck') [(4.0, 'Michael Phillips'), (3.0, 'Jack Matthews')]
或许有时候将物品与人对调并不会得出有意义的结论,但是大多情况下,还是有利于我们做出有意义的比较。为了向不同的个体推荐商品,在线零售商可能会收集用户购买记录,将商品与人对调——正如我们前面所做的——可以帮助零售商找到这些商品的潜在用户,这有助于在清仓处理某些商品时定向投放促销广告,规划广告投入。
六、那种方法更合适
既然基于用户的方法和基于物品的方法都能得出推荐结果,那么那种方法更好呢?两种方法表面看起来差不多,其实仔细分析的话,两种方法在实际操作中还是有差别的。
我们或许没有考虑到一点,那就是物品和用户的区别。一般来讲,对于一个购物网站:
1、商品数通常少于用户数
2、每种商品购买者的数量通常远大于每个购买者购买商品的数量
3、有的用户甚至不买或者只买几样商品,而一种商品通常有一定数量的人购买
4、商品数增长速度通常小于用户增长速度
所以,对于同样的相似度算法,一般会有:
1、商品间比较次数远小于用户间比较次数
2、商品可比较的空间维度更多,得到的相似度结果更可靠
3、基于商品的数据储存量小于基于用户的数据储存量(不买商品的用户远少于没被买过的商品)
4、基于商品的相似度列表不必及时更新,大处理量的运算任务可以转移到网站流量压力小时运行,
而对于基于用户的列表则需在新用户购买商品时的及时更新,而在计算中间又会有新用户加入
考虑到购物网站的情况,我们其实更倾向于选择基于商品的方法。
七、问题的拓展
以上的两种推荐方法,我们称为基于用户的物品的协同过滤和当然。
其实,两种方法各有利弊,如基于物品的方法也有存在冷启动(必须有物品的历史数据)等问题,具体的选取主要看情景:基于用户的协同过滤更适合亚马逊淘宝等购物网站,而基于物品的协同过滤更适合微博人人等社交网站——对于这些网站,物品比用户更多,更新也更频繁。
真正的实际操作中,任何单一的算法都不会得到最优的结果,常常需要多种方法的结合,我们称为组合推荐,而我们代码中的函数也远远不能满足大数据条件下的运算需求,为了降低运算复杂度,常常采用聚类算法将数据进行预处理,由于鄙人水平所限无法继续提供代码,后面补上。
最后给感兴趣的同志提供一些参考资料:
1、《集体智慧编程》第二章——提供推荐
http://www.ibm.com/developerworks/cn/web/1103_zhaoct_recommstudy2/index.html
3、推荐系统的常用算法概述 :
http://www.cnblogs.com/luchen927/archive/2012/02/01/2325360.html
4、百度百科——推荐系统 :
相关推荐
普通高中人工智能教学策略初探——基于人脸识别的“人工智能初步”模块教学设计 人工智能是当前最热门的技术之一,对于普通高中学生来说,学习人工智能可以帮助他们更好地适应未来技术的发展。普通高中人工智能教学...
基于开源GIS的决策支持系统初探——以制定江苏省经济发展策略为例,张广运,方育莹,将开源GIS软件——SharpMap与一种决策理论——可拓工程方法结合起来,通过选择江苏省为研究区域,利用设计的决策支持系统制定我省...
《大剧院智能化系统总体方案规划与设计初探——以琴台剧院为例》这篇文档,深入探讨了现代化大剧院在智能化系统设计方面的理论与实践。在这个信息化飞速发展的时代,智能化系统的引入不仅提升了剧院的运营效率,也为...
城市管理模式创新初探——北京市信息化城市管理系统建设.pdf
线上线下混合式教学路径初探——以Linux操作系统课程为例.pdf
浙江影天 为网络印刷铺路——无人值守型自动化印前系统初探.pdf
【标题】: "机器学习在图书馆知识发现系统中的应用初探——以基于知识图谱的发现工具Yewno为例" 【摘要】: 随着数字化资源的爆炸性增长,图书馆用户对于个性化和深层次知识发现的需求日益增强。在这种背景下,机器...
网络信息时代档案管理的方法初探——以高校教学档案管理为例 1. 档案管理方法的重要性 在信息时代,档案管理不仅是学校把握学生个人信息的关键,也是与学生日后就业、生活等有关键的环节。但是,随着网络技术的...
标题中的“浙江影天 为网络印刷铺路——无人值守型自动化印前系统初探”表明这是一份关于网络印刷领域中无人值守自动化印前系统的详细介绍。这种系统旨在提高印刷行业的生产效率,减少人工干预,实现24小时不间断的...
这篇博客“初探Druid连接池之三——进入内置监控页面(连接数据源后)”将引导我们深入了解如何在实际应用中启用并使用Druid的监控功能。 首先,Druid连接池的核心优势在于其对数据库连接的精细化管理,包括连接...
【标题】高职电子信息类专业群建设初探——以湖南铁道职业技术学院为例 【摘要】专业建设是高职教育人才培养的核心,本文以湖南铁道职业技术学院的电子信息专业群建设为例,探讨了在当前高质量技术技能型人才培养...
基于微信小程序的高中生物教学应用初探——以免疫调节为例
《基于CORBA的分布式应用软件网络性能初探——单次调用传输的数据量大小对有效吞吐量的影响》 本文探讨了在分布式应用软件中,尤其是针对导航系统,基于CORBA(Common Object Request Broker Architecture)的...
该系统包括闭路电视监控系统、防盗报警系统、资产防盗和人员定位系统、安保巡更系统、门禁系统、停车场管理系统、安检系统等多个子系统,通过集成平台实现了综合防范能力,提升了整体安全性能。 3. **通信自动化...
车路协同自动驾驶系统有四个显著特点:一是增强车与路之间的感知能力,二是实现全局视野的规划和决策,三是进行协同控制以优化系统管理,四是通过多重备份提高整体的安全性和稳定性。这种系统可以缩短自动驾驶从L1到...
这种方法降低了系统开发的门槛和成本,使得县级林业部门也能实现古树名木的信息化管理,对于古树的保护和研究具有积极意义。 【总结】 谷歌地球专业版和GIS/GPS的结合在古树名木地理信息系统中的应用,展示了现代...
其二,是病证结合模式,即在西医诊断的基础上,利用中医的望、闻、问、切四诊方法诊断证候,并研究证候与生物学系统指标之间的相关性。这种模式的研究目的在于推进中医诊断的客观化,挖掘证候的实质,并为医学临床的...
【微软高性能运算系列课程(1):WCCS初探——微软高性能运算平台】 高性能计算(High Performance Computing,HPC)是计算机科学的一个分支,它致力于解决需要大规模计算能力的问题。微软高性能运算平台(Microsoft ...
这些指标包括面向外部用户需求、教育系统需求、最小化系统性能、考虑教育管理不同层次需求等。这些原则强调了教育质量评估的多元化和综合化,以及评价体系与国际同行的可比性。 4. 高等教育市场竞争与筹资: 文档...