2012年11月17日星期六

Netflix 推荐系统:第一部分

原文链接:http://techblog.netflix.com/2012/04/netflix-recommendations-beyond-5-stars.html

在这篇包含两个部分的博文中,我们将揭开 Netflix 最有价值的资产——推荐系统的面纱。在第一部分,我们将介绍 Netflix Prize 对推荐领域的贡献,Netflix 推荐服务的主要模块,以及推荐服务如何满足网站的商业需求。在第二部分,我们将介绍我们使用的数据和模型,讨论如何将离线的机器学习实验与线上的 A/B 测试相结合。

Netflix Prize 和推荐系统
在 2006 年,我们宣布举办 Netflix Prize,这是一个旨在解决电影评分预测问题的机器学习和数据挖掘的比赛。对于那些能够将我们的推荐系统 Cinematch 的准确率提升 10% 的个人或团队,我们提供 100 万美金的奖励。我们希望通过比赛发现新的方法来改善我们提供给用户的推荐结果,这是我们商业模式的核心部分。当然,我们需要一个比较容易评测和量化的指标:我们选择的评测指标是均方根误差(RMSE,预测评分和真实评分之间的均方根误差)。比赛的要求是打败我们系统 0.9525 的 RMSE 得分,并将其降低到 0.8572 或更低。

比赛开始一年后,Korbell 的团队以 8.43% 的提升赢得了第一个阶段奖。他们付出了超过 2000 个小时的努力,融合了 107 种算法才得到了这份奖金。然后,他们将源代码交给了我们,我们分析了其中两种最有效的算法:矩阵分解(通常被叫做 SVD,奇异值分解)和局限型玻尔兹曼机(RBM)。SVD 取得 0.8914 的 RMSE,RBM 取得 0.8990 的 RMSE,将这两种方法线型融合能将 RMSE 降低到 0.88。为了将这些算法应用到我们的实际系统中,我们必须克服一些限制,例如比赛的数据集是一亿个评分,但实际的线上系统是 50 亿个,并且这些算法的设计并没有考虑用户不断产生的新评分。但最终我们克服了这些困难,并把这两种算法应用到了我们的产品中,而且作为我们推荐引擎的一部分一直被使用到现在。

如果你关注比赛的结果,可能对两年后大奖的归属很感兴趣。这是一项令人印象深刻的工作,数百种预测模型被融合在一起,最终突破了 0.8572 的临界线。我们评测了一些最新的离线算法,但是很遗憾,这些在比赛数据上胜出的算法,到了线上却表现不够出色。因此,我们并没有应用到我们的线上环境。与此同时,我们的关注点也从提升 Netflix 的个性化体验转移到了下一个层级。在下文中,我们将解释为什么要转移关注点?

从美国 DVD 租赁到全球视频流媒体服务
近几年,随着 Netflix 业务的发展,我们对推荐算法的关注点发生了变化。在 Netflix Prize 举办一年后的 2007 年,我们发布了实时流媒体服务。流媒体不仅改变了用户与系统的交互方式,也改变了推荐算法的的可用数据类型。对 DVD 租赁业务来说,目标是帮助用户找到电影,并在接下来的数天或数周内邮寄到用户邮箱。用户从选择电影到观看电影,期间有一个过程,在这个过程中收不到用户的任何反馈。一旦用户不满意,想要更换 DVD,代价会很大,需要花费一天以上的时间,所以用户一般会仔细挑选。而对流媒体用户来说,选一部电影立马就可以观看,甚至可以在很短时间内观看多部电影。同时,我们可以通过统计知道用户是看完了整部电影,还是只看了一部分。

另一个巨大的变化是,流媒体服务从单纯的 Web 网站扩展到了成百上千的不同设备。例如:Netflix 比赛举办后的两年,微软就发布了集成 Roku 播放器的 XBox。仅仅又过了一年,Netflix 发布了 iPhone 客户端。现在,各种 Android 和最新的 Apple TV 上都有 Netflix 的身影。

两年前,我们走向国际,推出了加拿大版本。2011 年,我们的服务扩展到了 43 个拉美国家和地区。最近,我们还登录了英国和爱尔兰。今天,Netflix 已经遍布 47 个国家,共有超过 2300 万的订阅用户。在 2011 年第一季度,这些用户通过上百种不同的设备观看了 20 亿个小时的视频。每天有 200 万部电影和电视剧被观看,并新增 400 万个用户评分。

我们已经在这些新的场景中添加了个性化服务,现在有 75% 的视频观看是与推荐系统有关的。我们取得这样的成绩源于我们不断优化用户体验,通过优化算法,我们改善了用户满意度。下面我们列举一些使用在推荐系统中的技术和算法。

推荐无处不在
经过几年的实践,我们发现尽可能的集成个性化推荐到功能中,会对我们的订阅用户产生巨大的价值。我们的个性化从首页就开始了,包括按行展示的视频,每一行有一个主题,主题揭示了这行视频的内在联系。大多数个性化都是基于挑选行视频的方法,包括哪些行该放那些视频,以及如何对视频进行排序。

以顶部的 10 行为例:我们猜测这是你最可能喜欢的 10 个主题。当然,我们说“你”的时候也包含了你的家人。值得注意的是,Netflix 的个性化是针对每一个家庭,而一个家庭的不同成员会有不同的兴趣和口味。这也就是为什么要选 10 行的原因,你可能会发现这 10 行已经涵盖了对爸爸、妈妈、小孩或者整个家庭的推荐。即使这个家庭只有一个用户,我们也希望能兼顾到这个用户的不同兴趣和情绪。为了做到这一点,我们系统的不仅要提高准确度,还要提高推荐结果的多样性。

Netflix 个性化推荐系统的另一个重要元素是认知(awareness)。我们想让用户知道我们是如何把握他们的喜好。这不仅能让用户信任我们的系统,而且还能鼓励用户提交更多的反馈来帮助我们把推荐做得更好。提升个性化推荐信任度的另一种方法是提供推荐理由,为什么我们要推荐这部电影或电视剧?我们不是因为商业需求给用户推荐,而是基于我们从用户那里获得的信息,包括:用户评分、观看记录、用户好友的推荐等等。

关于基于好友的推荐,我们最近在 47 个服务国家中的 46 个发布了我们的 Facebook 连接组件。这第 47 个就是美国,因为受VPPA(《录像隐私权保护法案》,1998)的影响。朋友了解的内容不仅仅为我们的推荐算法提供了另一个数据来源,也使我们能够以社交圈生成几行新的推荐结果。

我们的推荐服务中最让人印象深刻的一点便是“风格”为主题的几行推荐结果。这里既包含了像“喜剧”这样的大类,也包含了像“时空穿越”这样长尾里面的小类。每一行的展现都考虑了三个方面:选择哪一种风格,选择这个风格里的哪些视频,这些视频如何排序。用户对这个模块的关注度是很高的,当我们把长尾里的类别放到前面的时候,检测到用户的停留时间有明显的增长。其他的诸如新颖性和多样性也是推荐服务考虑的重要因素,以便为用户生成上千种可能的视频组合。

我们也为每一行的选择提供了推荐理由。有些是基于隐式反馈,如:最近观看记录、用户评分和其他交互;有些是基于显示反馈,显示反馈是通过我们邀请用户来做口味偏好调查得来的。

基于相似性的推荐也是我们个性化推荐服务的一个重要部分。相似性是一个很宽泛的概念,描述的对象可以是不同的电影、用户,也可以是评分、视频元信息等。此外,这些相似性可以混合作为其他模块的特征。相似性也可以用在多种场景之中,例如:当用户搜索一部电影或者把一部电影放到播放列表的时候,可以为用户生成“特定风格”的推荐结果,这些结果是基于用户最近关注过的视频。如果你对相似性系统的体系结构感兴趣,想进行一些深入的了解,可以关注我们过去的博客

上述的场景中,包括优选的 10 行推荐、风格推荐、基于相似性的推荐,都要涉及到排序算法,即:选择什么样的顺序来排列每一行中的视频,这是提供有效推荐结果的关键一步。排序系统的目标是在特定的场景下实时的为一组视频找到最佳的排列顺序(简单说就是把用户最感兴趣的视频排列在前)。我们将排序系统的任务分解为:评分、排序、过滤。我们的商业目标是最大化用户的满意度和每月订阅保有量,这实际上等价于最大化用户的视频观看次数。因此,我们优化我们的算法,对那些用户最可能观看和喜欢的视频给最高的分数。

现在我们已经明确的知道 Netflix Prize 的目标是提高电影评分预测的准确度,这只是一个有效的推荐系统众多构成的一种。我们还需要考虑像用户场景、视频流行度、用户兴趣、可解释性、新颖性、多样新和惊喜度等方方面面。为了考虑这些因素,我们要挑选合适的算法。在本文的第二部分,我们将详细的讨论排序问题,深入探讨的我们的数据和模型,以及我们所作的一些创新工作。

————————————————————————————————————
这篇 blog 分两部分,内容很长。第一部分介绍的内容并没有透露任何技术细节,主要是介绍了 Netflix 推荐系统的产品形式(推荐场景)以及 Netflix Prize 带给他们的收益,感觉像是产品经理写写出来的:),但是 blog 的第二部分:排序还是透露了不少技术细节。详见:

Netflix 推荐系统:第二部分

2012年11月8日星期四

什么是好的推荐算法

2009 年 Greg Linden 在 Communication ACM 上发表了一篇文章《What is a Good Recommendation Algorithm》,文章质疑了评分预测推荐算法的意义, 认为 TopN 更有价值和意义。


Netflix 为一个更好的推荐引擎提供了一百万美金的奖励。更好的推荐很显然是非常有价值的。

但是,什么是更好的推荐?为了获得更好的推荐,我们要做些什么?
在 Netflix Prize,更好的含义是非常具体的。评测的标准是:Netflix 用户对电影的真实打分和算法预测的用户打分之间的均方根误差(RMSE)。

比方说我们构建了一个赢得了比赛的推荐引擎。我们的算法使 Netflix 能够将预测值和用户的真实打分之间的误差降低 10% 以上。这是好的推荐算法吗?

根据我们的期望,这可能是一个不错的算法。如果我们希望显示用户喜欢一部电影的程度(用户的评分),同时对于每一部电影预测的评分值要尽可能准确。

然而,这可能不是我们想要的。相对于在产品功能上显示用户喜欢一些特定的电影的程度,用户更在意一些极端的错误情况。例如:将一部你喜欢的电影(真实打分为 4.5 分)预测为一般般(预测打分为 3.5 分)和将一部你觉得一般般的电影(真实打分为 3.5 分)预测为非常一般(预测打分为 2.5 分),对于用户来说,前者显得非常糟糕。

此外,我们经常希望不要去预测用户看了电影之后会给电影什么样的评分,而是希望帮忙找到用户最感兴趣的电影。TopN 推荐为用户挑出最感兴趣的 10 个左右的物品。即使不能预测哪些人会厌恶或者是不喜欢也没关系。TopN 关心的仅仅是挑出用户将会喜欢的 10 个物品。

擅长对所有电影进行预测评分的推荐引擎并不一定能很好的预测排名靠前的 N 部电影。均方根误差(RMSE)加大了对于预测不准的电影评分的惩罚,但对于一些不错的电影,也许我们真正关心的是最小误差。

这和 Web 搜索有相似之处。搜索引擎主要关心查准率(排名前 10 或排名前 3 的相关结果)。当人们看到的结果中缺少他们需要的内容时,他们仅仅只关心召回率。搜索引擎不关心关于文档的错误得分,它只是尽力找到排名前 N 的文档。

进一步探讨这个问题,在推荐系统和搜索引擎领域,人们的看法很容易受到物品以外的因素影响。人们讨厌网速慢的网站,认为结果加载慢的网站要比加载快的网站糟糕很多。对于每个物品提供的信息上的差异(特别是数据丢失或拼写错误)会影响用户感知。结果的呈现,那怕是超链接的颜色,都有可能影响用户的注意力,影响用户查看推荐结果。当推荐引擎能够向用户解释为什么给他推荐的时候,用户才能够更多的信任推荐结果。同时当用户提供了一些新的有价值的信息之后,希望推荐结果能够立即得到更新。多样性是有价值的;重复让人讨厌。新物品吸引眼球,但用户还是能够很粗糙的判断出那些不熟悉和陌生的推荐结果。

最后,我们希望用户能够快乐,满足。但是一个推荐引擎最大限度地减少均方根误差能让人快乐吗?

2012年11月6日星期二

推荐引擎反思

原文链接:http://readwrite.com/2008/02/24/rethinking_recommendation_engines

两年多年(2006年),Netflix 宣布举办推荐引擎大赛——对于能将 Netflix 的推荐系统(Cinematch)精准度提高 10% 的 team 或个人,将给予 1 百万美金的奖励。许多 team 争相参与破解这个问题,并为能使用这些前所未有的可用数据而感到兴奋。最初各支 team 的进步都很可观,但慢慢的算法的可提升空间开始止步不前,最终各支 team 的结果提升大都停留在了 8.5% 左右。

在这篇文章中,我们会讨论推荐引擎的改善不仅仅是一个算法问题,还是一个呈现问题。以过滤代替推荐,同时交付给用户的时候不要设置过高的期望,会比处理很多数据快很多。

构建一个推荐引擎是一项复杂的工作,这个我们一年前讨论过。除了技术上挑战难度的增加,也有一些根本的心理问题:人们希望推荐,如此一来,我们什么时候给用户推荐呢?也许一个更大的问题是:当用户收到不是他们想要的推荐的时候,用户该如何宽容我们?

推荐引擎遗传学
所有推荐引擎都在尝试解决以下问题:给定一个特定用户的评分,以及整个用户群,想出将会喜欢的新物品。有许多算法能用来解决这个问题,但是所有这些算法都集中于三个要素:个人的,社会化的和基本的。
  • 个性化的推荐:基于用户过去的行为进行推荐
  • 社会化的推荐:基于相似用户过去的行为进行推荐
  • 基于 item 的推荐:基于 item 本身(如内容相似形)的推荐
  • 前面三种方法的混合推荐

社会化的推荐也被称为协同过滤 —— 喜欢 X 的用户也喜欢 Y。例如:喜欢《指环王》的用户很可能会喜欢《龙骑士》和《纳尼亚传奇》。这个推荐方法的问题在于现实中难以对人们的口味进行一个简单的分类。如果两个用户对于科幻电影有着共同的喜好,并不意味着他们在戏剧和悬疑剧上也有着相似的喜好。从遗传学的角度来看待这个问题是一个比较好的方法。很多时候我们遇到人们有一些我们熟悉的特征,这些特征在其他人身上也能看到。例如:眼睛可能很面熟,或者是嘴唇,但是他们确是完全不同的人种。

另一种推荐是基于 item 的推荐。这种推荐系统最好的例子的就是 Pandora 的音乐推荐服务。Pandora 为每首音乐标注了 400 多个特征,这些特征可以形象的称为“音乐基因”,Pandora 就是基于这些“音乐基因”进行工作的,它会根据这些“基因”自动匹配音乐。然而这种方法在算法调优上有很大的挑战,并且想要把类似的方法应用在其他类型的垂直网站也是一件非常有挑战的事情。例如:对于电影,你需要考虑从哪些维度评测一部电影,从导演,演员,剧情;还有一些比较模糊的如音效,场地,灯光,摄影等等。这些电影一定会有的东西,但却很复杂。

车库里的家伙
推荐问题的复杂性在于它广泛的可能性。具体说就是:对于某一个具体的人,很难准确的确定哪一些基因适用于他,很难指出一部电影或一首音乐的哪些基因让我们给它打 5 分。转变工程师的思维是很困难的。这就是为什么《连线》文章中强调参赛者们使用了一种非常罕见的技巧来使他的算法有效运行。

这个家伙来自伦敦的 Gavin Potter,网名 Guy In The Garage(车库里的家伙),他的方法依赖了人的惰性。很显然,对电影的评分依赖于我们之前看过的电影的评分。例如:如果你连续观看了三部电影,并给它们打了 4 分,那么当你看到下一部稍好一点的电影时,你将会打 5 分。反之,如果你连续给三部电影打了 1 分,那么当你看到和刚刚一样的一部 5 分的电影时,你可能只会打 4 分。

当你还在思索这是不是真的的时候,你将会发现这类算法现在已经占据了第 5 类推荐算法的位置,并在不断的发展,情况远远比其他的算法好。通过一点心理学的知识来强化数学公式无疑是一个好办法,这也是我们接下来要谈及的问题。

用过滤取代推荐
有多少次这样的情况发生在你身上:朋友向你推荐了一部电影或一个宾馆,你兴高采烈的去了,但却败兴而归?很多!很显然,炒作使得期望的门槛变高了。用数学术语讲,这种类型的错误被称为假阳性。现在考虑这样的一种情况,如果你的朋友不是给你推荐一部电影,而是告诉你你肯定不会喜欢的一部电影,这样你就不用花钱去租它了。这种情况下会发生什么呢?

这种情况会带来什么坏处呢?答案是不会有什么坏处,因为你很可能就不会去看这部电影。但即使你真的看了这部电影并且喜欢这么电影,你也不会有负面的情绪。(相反你会感到很惊喜,哇塞!原来这部电影这么棒)。这个例子充分说明了用户对于假阳性和假阴性错误的不同反应。假阳性使我们感到沮丧,但假阴性不会。以过滤代替推荐的思想就是为了平衡这样的一种现象。

当 Netflix 作出推荐时,它总会有一定的出错比例。或早或晚,错误将会出现,推荐一部你不喜欢的电影给你。如果推荐系统不是这样做,而是推荐给你新电影,同时有一个按钮:把那些你不喜欢的电影过滤掉。同样的算法,但是感受确是不一样的。

实时过滤
在实时新闻的时代,这种想法变得越发重要和强大。我们越发需要对新的信息进行连续的过滤。就像我们每天都用 RSS 阅读器过滤文章一样。从新闻流的角度来看这个世界,过去的事情都是不相关的。我们不需要推荐,因为我们已经订阅了很多的内容。我们需要过滤掉噪音。需要一个算法说:“嗨,你一定不会喜欢这个东西的,把它隐藏掉吧!”。

如果机器能做到那样,积极地把我们周围无用的信息扔开,那么剩下的我们就可以自己来处理了。借鉴邮件过滤系统,如果我们身边的工具都有一个按钮:“帮我把这个过滤掉”,并且这个工具可能还是默认启动的,那么我们就能做更多的事情了。

结论
构建一个完美的推荐引擎是一项非常复杂的任务。不管使用什么方法,协同过滤或基于物品属性的推荐,都是不会被原谅的商业工具,假阳性的错误会让用户逐渐流失。可能把心理学应用于这个问题,可以让用户懂得感激这些复杂算法所做的事情。如果系统过滤掉那些我们一定不喜欢的东西,而不是给我们推荐一堆东西,我们可能会更加宽容和给予更多的理解。

现在请告诉我对于推荐引擎你的一些经验。你的推荐引擎真的工作的很好吗?你是否会用开放的过滤取代推荐?除了电影和新闻,你会在哪些地方使用过滤器?

2012年10月27日星期六

QCon 杭州2012参会小记

2012年10月27日,QCon 杭州2012 日程的最后一天,我幸运的从同事那里得到了一张讲师的门票,然后以听者的身份去参会。一共听了 6 场分享,如下:

facebook 的《HBase Solutions at Facebook》,演讲的 Nicolas 是位大帅哥,声音很清脆。HBase 在 facebook 的多个重要大型系统中得到深入应用,包括著名的 Message系统。只可惜我对 HBase 没有实战经验,所以听的很懵,但是对于 facebook 的数据规模还是相当震撼,根据 PPT 的介绍,目前 facebook 运行在 HBase 上的 Message 系统每月处理 1800 亿条 P2P 消息。
HBase Solutions at Facebook

毕玄的《T4:淘宝私有云》讲的的很实际,介绍了 T4 虚拟化方案的问题和选择,资源分配、动态调整(平滑扩容)、平衡、监控、自动化,还特别分享了 T4 实践中遇到的一些问题以及未来的优化思路。T4 着力于大幅度降低淘宝的运维成本,演讲中多次提到为了解决某些问题,不得不修改内核,大牛做事就是够彻底。因为 T4 是自己家的东西,所以以后还会有很多机会进行了解。

Dave Thomas(《程序员修炼之道》作者)的《敏捷,以及敏捷的腐化》,《Old Ways,New Ways》讲的都非常质朴,演讲是从给自我打标签开始的,俨然一开始就上升到人生哲学的高度。Dave 特别提到敏捷要因时而变,切勿盲目套用方法论,要多实践,多操练,不要害怕犯错,要让敏捷成为一种习惯和不用思考的东西。此外还提到 1W 小时练习定理,并告诫在场的开发者系统开发要注重设计架构和代码重构,切勿重复造轮子。能够听到 Dave 现场布道真的很幸运,Dave 还专门讲到做事情要 be a verb, not a noun…,大师就是大师,大道至简。另外不得不提的是 Dave 做演讲相当个性,直接光脚上阵演讲,哈哈~
Dave Thomas
Old Ways,New Ways

大众点评这次的主题是关于网站监控平台的构建,大众点评的监控系统出师于 eBay 的 CAL 监控系统,所以名字来也很接近,叫 CAT。CAT 集成了应用监控、运维、容量规划及业务数据监控于一身。CAT 的监控元数据是直接从 App 传回监控系统的,不会存储在 App 本地,同时 CAT 抽象了一套非常简单的 API,方便 App 接入,不过对于元数据的模型没有太详细的介绍。

最后一场听的是方越的《从另一个角度看世界》。方越是一名开源项目开发者,任职于 Red Hat,是多个 Apache 项目的 PMC Member 和 Committer,团队里的15名成员分布在8个不同国家,最让人羡慕的是他们都是在家里上班,通过全球协作的方式进行工作(太先进了)。“周围人的水平决定了你的水平;做对的事情比把事情做对更重要;你的时间在哪里,你的成就就在哪里”,方越的 PPT 不多,但是让人印象深刻。

能够参加 QCon 真的很幸运,听到的东西虽然不能马上运用在工作中,但是他们的曲折经历,踏过的坑、迈过的坎,积累的经验值得我们学习,总之获益匪浅。另外,参会的一个特别感受就是:男厕队列繁忙,响应缓慢,而女厕却是资源异常空闲~~

2012年6月8日星期五

Mahout 之(四)Taste的架构和部署Demo

Taste简介
Taste是Apache Mahout提供的一个协同过滤算法的高效实现,它是一个基于Java实现的可扩展的,高效的推荐引擎。Taste既实现了最基本的基于用户的和基于内容的推荐算法,同时也提供了扩展接口,使用户可以方便的定义和实现自己的推荐算法。同时,Taste不仅仅只适用于Java应用程序,它可以作为内部服务器的一个组件以HTTP和Web Service的形式向外界提供推荐的逻辑。Taste的设计使它能满足企业对推荐引擎在性能、灵活性和可扩展性等方面的要求。

Taste的架构
Taste Architecture

Taste由以下五个主要的组件组成:

  • DataModel:DataModel是用户喜好信息的抽象接口,它的具体实现支持从任意类型的数据源抽取用户喜好信息。Taste默认提供JDBCDataModel和FileDataModel,分别支持从数据库和文件中读取用户的喜好信息。
  • UserSimilarity和ItemSimilarity:UserSimilarity用于定义两个用户间的相似度,它是基于协同过滤的推荐引擎的核心部分,可以用来计算用户的“邻居”,这里我们将与当前用户口味相似的用户称为他的邻居。ItemSimilarity 类似的,计算内容之间的相似度。
  • UserNeighborhood:用于基于用户相似度的推荐方法中,推荐的内容是基于找到与当前用户喜好相似的“邻居用户”的方式产生的。UserNeighborhood定义了确定邻居用户的方法,具体实现一般是基于 UserSimilarity 计算得到的。
  • Recommender:Recommender是推荐引擎的抽象接口,Taste中的核心组件。程序中,为它提供一个DataModel,它可以计算出对不同用户的推荐内容。实际应用中,主要使用它的实现类 GenericUserBasedRecommender或者GenericItemBasedRecommender,分别实现基于用户相似度的推荐引擎或者基于内容的推荐引擎。

运行Demo
1. 下载mahout-0.2
    svn checkout https://svn.apache.org/repos/asf/mahout/branches/mahout-0.2/
2. 准备数据源,从Grouplen下载"1 Million MovieLens Dataset",链接:http://www.grouplens.org/system/files/ml-1m.zip
3. 解压数据源压缩包,将movie.dat和ratings.dat拷贝到/mahout-0.2/examples/src/main/java/org/apache/mahout/cf/taste/example/grouplens
4. 回到/mahout-0.2/examples目录下,运行"mvn install"
5. 进入/mahout-0.2/taste-web目录,拷贝 ../examples/target/grouplens.jar到 taste-web/lib目录
    cp ../examples/target/grouplens.jar ./lib
6. 在/mahout-0.2下运行"mvn package"
7. 将 taste-web/target 目录下生成的war包“mahout-taste-webapp-0.2.war”拷贝到Tomcat的webapp下
8. 启动Tomcat,在/bin目录运行“./startup.sh”
9. 访问“http://localhost:8080/mahout-taste-webapp-0.2/RecommenderServlet?userID=1”
Build Demo

2012年4月19日星期四

Hadoop基础篇之(一)安装部署

1. 下载hadoop
从http://hadoop.apache.org/common/releases.html下载一个hadoop的发行版本,此处使用wget方式,wget http://mirror.bjtu.edu.cn/apache/hadoop/core/hadoop-1.0.2/hadoop-1.0.2.tar.gz

解压下载的压缩包到 home/<your dictionary>/hadoop
tar –zvxf hadoop-1.0.2.tar.gz

2. set JAVA_HOME / PATH
打开.bash_profile文件
$ vi ~/.bash_profile

export JAVA_HOME=<path-to-java>
export PATH=$PATH:<path-to-java>/bin

保存退出,查看配置是否成功
$ echo $JAVA_HOME
$ echo $PATH

HADOOP_HOME是可选的,并且在hadoop-1.0.2下,配置HADOOP_HOME会抛一个警告:“Warning: $HADOOP_HOME is deprecated.”,所以实际配置中,可以不用设置HADOOP_HOME

检查配置是否成功
$ bin/hadoop
打印以下内容说明配置成功
Usage: hadoop [--config confdir] COMMAND
where COMMAND is one of:
  namenode -format     format the DFS filesystem
  secondarynamenode    run the DFS secondary namenode
  namenode             run the DFS namenode
  datanode             run a DFS datanode
  ...

伪分布式模式的配置

3. 配置相关配置文件
(1) conf/core-site.xml:
<configuration>
  <property>
    <name>fs.default.name</name>
    <value>hdfs://localhost:9000</value>
  </property>
</configuration>

(2) conf/hdfs-site.xml:
<configuration>
  <property>
    <name>dfs.replication</name>
    <value>1</value>
  </property>
</configuration>

(3) conf/mapred-site.xml:
<configuration>
  <property>
    <name>mapred.job.tracker</name>
    <value>hdfs://localhost:9001</value>
  </property>
</configuration>

4. 免密码ssh设置
现在确认能否不输入口令就用ssh登录localhost:
$ ssh localhost

如果不输入口令就无法用ssh登陆localhost,执行下面的命令:
$ ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
$ cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys

5. 执行
(1) 格式化分布式文件系统:
$ bin/hadoop namenode -format

(2) 启动Hadoop守护进程:
$ bin/start-all.sh
Hadoop守护进程的日志写入到 ${HADOOP_LOG_DIR} 目录 (默认是 ${HADOOP_HOME}/logs)

(3) 运行示例程序:
将输入文件拷贝到分布式文件系统:
$ bin/hadoop fs -mkdir input
$ bin/hadoop fs -put conf input
运行发行版提供的示例程序:
$ bin/hadoop jar hadoop-examples-*.jar grep input output 'dfs[a-z.]+'

查看输出文件:
将输出文件从分布式文件系统拷贝到本地文件系统查看:
$ bin/hadoop fs -get output output
$ cat output/*

浏览NameNode和JobTracker的网络接口,它们的地址默认为:
NameNode - http://localhost:50070/
JobTracker - http://localhost:50030/

6. 停止守护线程
完成全部操作后,停止守护进程:
$ bin/stop-all.sh

7. 实战——WordCount
WordCount在Hadoop主目录下的java程序包hadoop-examples-1.0.2.jar 中
重新启动守护线程:
$ bin/start-all.sh
建立一个新目录,此处命名为testfile
$ bin/hadoop fs -mkdir testfile
在本地/home/usr/hadoop/tmp目录中建立一个txt文件test.txt,并填写如下内容:
hello world
hello I am a engineer
world peace
然后将此文件copy到分布式文件系统的testfile里:
$ bin/hadoop fs -put /home/usr/hadoop/tmp/test.txt testfile

执行wordcount程序:
$ bin/hadoop jar hadoop-examples-1.0.2.jar wordcount testfile output
注意:在执行上面的命令之前,需要先删除分布式文件系统中的output目录,因为hdfs中job之间的输出目录是不允许重复的,否则会抛如下的错误:
‘org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory output already exists’
删除命令:
$ bin/hadoop dfs -rmr output

查看执行结果:
$  bin/hadoop dfs -cat output/part-r-00000
I           1
a           1
am          1
engineer    1
hello       2
peace       1
world       2

2012年4月4日星期三

Mahout 之(三)相似性度量

User CF 和 Item CF 都依赖于相似度的计算,因为只有通过衡量用户之间或物品之间的相似度,才能找到用户和物品的“邻居”,才能完成推荐。上文简单的介绍了相似性的计算,但不完全,下面就对常用的相似度计算方法进行详细的介绍:

1. 基于皮尔森相关性的相似度 —— Pearson correlation-based similarity
皮尔森相关系数反应了两个变量之间的线性相关程度,它的取值在[-1, 1]之间。当两个变量的线性关系增强时,相关系数趋于1或-1;当一个变量增大,另一个变量也增大时,表明它们之间是正相关的,相关系数大于0;如果一个变量增大,另一个变量却减小,表明它们之间是负相关的,相关系数小于0;如果相关系数等于0,表明它们之间不存在线性相关关系。

用数学公式表示,皮尔森相关系数等于两个变量的协方差除于两个变量的标准差。
 Pearson Correlation

协方差(Covariance):在概率论和统计学中用于衡量两个变量的总体误差。如果两个变量的变化趋于一致,也就是说如果其中一个大于自身的期望值,另一个也大于自身的期望值,那么两个变量之间的协方差就是正真;如果两个变量的变化趋势相反,则协方差为负值。
协方差

其中u表示X的期望E(X), v表示Y的期望E(Y)

标准差(Standard Deviation):标准差是方差的平方根
标准差

方差(Variance):在概率论和统计学中,一个随机变量的方差表述的是它的离散程度,也就是该变量与期望值的距离。
方差

即方差等于误差的平方和的期望

基于皮尔森相关系数的相似度有两个缺点:
(1) 没有考虑(take into account)用户间重叠的评分项数量对相似度的影响;
(2) 如果两个用户之间只有一个共同的评分项,相似度也不能被计算
 Table1 Pearson Correlation 的缺点

上表中,行表示用户(1~5)对项目(101~103)的一些评分值。直观来看,User1和User5用3个共同的评分项,并且给出的评分走差也不大,按理他们之间的相似度应该比User1和User4之间的相似度要高,可是User1和User4有一个更高的相似度1。

同样的场景在现实生活中也经常发生,比如两个用户共同观看了200部电影,虽然不一定给出相同或完全相近的评分,他们之间的相似度也应该比另一位只观看了2部相同电影的相似度高吧!但事实并不如此,如果对这两部电影,两个用户给出的相似度相同或很相近,通过皮尔森相关性计算出的相似度会明显大于观看了相同的200部电影的用户之间的相似度。

Mahout对基于皮尔森相关系数的相似度给出了实现,它依赖一个DataModel作为输入。
PearsonCorrelationSimilarity

同时,Mahout还针对缺点(1)进行了优化,只需要在构造PearsonCorrelationSimilarity时多传入一个Weighting.WEIGHTED参数,就能使有更多相同评分项目的用户之间的相似度更趋近于1或-1。
UserSimilarity similarity1 = new PearsonCorrelationSimilarity(model);
double value1 = similarity1.userSimilarity(1, 5);

UserSimilarity similarity2 = new PearsonCorrelationSimilarity(model, Weighting.WEIGHTED);
double value2 = similarity2.userSimilarity(1, 5);

结果:
Similarity of User1 and User5: 0.944911182523068
Similarity of User1 and User5 with weighting: 0.9655694890769175

2. 基于欧几里德距离的相似度 —— Euclidean Distance-based Similarity
欧几里德距离计算相似度是所有相似度计算里面最简单、最易理解的方法。它以经过人们一致评价的物品为坐标轴,然后将参与评价的人绘制到坐标系上,并计算他们彼此之间的直线距离。
欧几里德距离
Table2 通过欧几里德距离计算相似性

图中用户A和用户B分别对项目X、Y进行了评分。用户A对项目X的评分为2,对项目Y的评分为4,表示到坐标系中为坐标点A(1.8, 4);同样用户B对项目X、Y的评分表示为坐标点B(4.5, 2.5),因此他们之间的欧几里德距离(直线距离)为:sqrt((B.x - A.x)^2 + (A.y - B.y)^2)
Euclidean Distance

计算出来的欧几里德距离是一个大于0的数,为了使其更能体现用户之间的相似形,可以把它规约到(0, 1]之间,具体做法为:1 / (1 + d)。参见 Table2
Euclidean Distance-based Similarity

只要至少有一个共同评分项,就能用欧几里德距离计算相似度;如果没有共同评分项,那么欧几里德距离也就失去了作用。其实照常理理解,如果没有共同评分项,那么意味着这两个用户或物品根本不相似。

3. 余弦相似度 —— Cosine Similarity
余弦相似度用向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小。相比距离度量,余弦相似度更加注重两个向量在方向上的差异,而非距离或长度上。
Cosine Similarity

与欧几里德距离类似,基于余弦相似度的计算方法也是把用户的喜好作为n-维坐标系中的一个点,通过连接这个点与坐标系的原点构成一条直线(向量),两个用户之间的相似度值就是两条直线(向量)间夹角的余弦值。因为连接代表用户评分的点与原点的直线都会相交于原点,夹角与小代表两个用户越相似,夹角越大代表两个用户的相似度越小。同时在三角系数中,角的余弦值是在[-1, 1]之间的,0度角的余弦值是1,180角的余弦值是-1。

借助三维坐标系来看下欧氏距离和余弦相似度的区别:
Distance and Cosine 3-Coordinates

从图上可以看出距离度量衡量的是空间各点间的绝对距离,跟各个点所在的位置坐标(即个体特征维度的数值)直接相关;而余弦相似度衡量的是空间向量的夹角,更加的是体现在方向上的差异,而不是位置。如果保持A点的位置不变,B点朝原方向远离坐标轴原点,那么这个时候余弦相似度cosθ是保持不变的,因为夹角不变,而A、B两点的距离显然在发生改变,这就是欧氏距离和余弦相似度的不同之处。

根据欧氏距离和余弦相似度各自的计算方式和衡量特征,分别适用于不同的数据分析模型:欧氏距离能够体现个体数值特征的绝对差异,所以更多的用于需要从维度的数值大小中体现差异的分析,如使用用户行为指标分析用户价值的相似度或差异;而余弦相似度更多的是从方向上区分差异,而对绝对的数值不敏感,更多的用于使用用户对内容评分来区分用户兴趣的相似度和差异,同时修正了用户间可能存在的度量标准不统一的问题(因为余弦相似度对绝对数值不敏感)。

Mahout没有专门给出基于余弦相似度的实现。

4. 调整余弦相似度 —— Adjusted Cosine Similarity
在余弦相似度的介绍中说到:余弦相似度更多的是从方向上区分差异,而对绝对的数值不敏感。因此没法衡量每个维数值的差异,会导致这样一个情况:比如用户对内容评分,5分制,X和Y两个用户对两个内容的评分分别为(1,2)和(4,5),使用余弦相似度得出的结果是0.98,两者极为相似,但从评分上看X似乎不喜欢这2个内容,而Y比较喜欢,余弦相似度对数值的不敏感导致了结果的误差,需要修正这种不合理性,就出现了调整余弦相似度,即所有维度上的数值都减去一个均值,比如X和Y的评分均值都是3,那么调整后为(-2,-1)和(1,2),再用余弦相似度计算,得到-0.8,相似度为负值并且差异不小,但显然更加符合现实。

5. 斯皮尔曼相关 —— Spearman Correlation
注:在Google上搜了下相关概念,理解的不是很明白~所以此处只是结合Mahout中的实现进行说明。
斯皮尔曼相关性可以理解为是排列后(Rank)用户喜好值之间的Pearson相关度。《Mahout in Action》中有这样的解释:假设对于每个用户,我们找到他最不喜欢的物品,重写他的评分值为“1”;然后找到下一个最不喜欢的物品,重写评分值为“2”,以此类推。然后我们对这些转换后的值求Pearson相关系数,这就是Spearman相关系数。

斯皮尔曼相关度的计算舍弃了一些重要信息,即真实的评分值。但它保留了用户喜好值的本质特性——排序(ordering),它是建立在排序(或等级,Rank)的基础上计算的。

回顾前面表中User1~5对Item101~103的喜好(评分)值,通过斯皮尔曼相关系数计算出的相似度为:
Table 3 Spearman Correlation

我们发现,计算出来的相似度值要么是1,要么是-1,因为这依赖于用户的喜好值和User1的喜好值是否趋于“一致变化”还是呈“相反趋势变化"。

Mahout对斯皮尔曼相关系数给出了实现,具体可参考SpearmanCorrelationSimilarity,它的执行效率不是非常高,因为斯皮尔曼相关性的计算需要花时间计算并存储喜好值的一个排序(Ranks),具体时间取决于数据的数量级大小。正因为这样,斯皮尔曼相关系数一般用于学术研究或者是小规模的计算。
UserSimilarity similarity1 = new SpearmanCorrelationSimilarity(model); // construct a Spearman Correlation-based Similarity
User1 to User1 : 1.0
User2 to User1 : -1.0
User3 to User1 : NaN
User4 to User1 : 1.0
User4 to User1 : 1.0

考虑到Spearman Correlation的效率,可以把SpearmanCorrelationSimilarity包装一层Cache,具体做法为:
UserSimilarity similarity2 = new CachingUserSimilarity(new SpearmanCorrelationSimilarity(model), model);
这样,每次计算的结果会直接放入Cache,下一次计算的时候可以立即得到结果,而不是重新再计算一次。

6. 基于谷本系数的相似性度量 —— Tanimoto Coefficient-based Similarity
Tanimoto Coefficient和前面的5中相关度计算方式有很大的不同,它不关心用户对物品的具体评分值是多少,它在关心用户与物品之间是否存在关联关系。还记得上一篇文章《Mahout学习笔记——数据承载》里面提到的布尔喜好值(Boolean Preference)吧!Tanimoto Coefficient依赖于用户和物品之间的这种Boolean关系作为输入。

更准确的说法为:Tanimoto Coefficient主要用于计算符号度量或布尔值度量的个体间的相似度,因为个体的特征属性都是由符号度量或者布尔值标识,因此无法衡量差异具体值的大小,只能获得“是否相同”这个结果,所以Tanimoto Coefficient只关心个体间共同具有的特征是否一致这个问题。Tanimoto Coefficient又被叫做Jaccard Coefficient,其值等于两个用户共同关联(不管喜欢还是不喜欢)的物品数量除于两个用户分别关联的所有物品数量。
Union/Intersection

也就是关联的交集除于关联的并集,用公式表示为:
Tanimoto/Jaccard Coefficient

其值介于[0, 1]之间,如果两个用户关联的物品完全相同,交集等于并集,值为1;如果没有任何关联,交集为空,值为0。

注:本块中说道的关联指用户对物品有评分值