mahout in action 中文翻译html
1. 初识Mahoutjava
本章涵盖如下内容:node
读者可能从本书的标题中依然知晓,本书是一本使用的工具书,讲解如何将mahout应用于业界。Mahout是Apache开源的机器学习库。它实现的算法都被纳入机器学习或者集体智慧的范畴,可是在这里Mahout主要注重协同过滤/推荐引擎、聚类和分类。linux
Mahout是可伸缩的。Mahout致力于实现海量数据,单机没法处理状况下的机器学习工具。在目前阶段,这种可伸缩性由java实现,有些部分基于Apache Hadoop这个分布式计算框架实现。算法
Mahout是java库。它不支持用户接口,预装好的服务器。以及安装等功能。它是一个利于开发者使用的工具框架。数据库
1.1 Mahout适合你吗?apache
你也许想知道-Mahout是一个什么工程,或者是一本什么书?编程
若是你在找一本机器学习的教材,那本书就不适合了。本书没有尝试去全面解释各类算法和展示技术的理论基础和来源。阅读本书能够,但不保证,可以对机器学习技术,相似矩阵、向量等相关概念的熟悉。windows
若是你正在开发现代智能应用,那本书很适合。这本书提供了一种实践非理论的处理方式,有完整的实例、解决方法指南。这本书在展现Mahout如何展现解决这些问题的时候,证实了一些被有经验的开发者收集的独特看法。数组
若是你是一我的工智能、机器学习以及相关领域的研究者,也适合用本书。你最大的挑战就是将一个新算法代码实现,Mahout提供了一个丰富的框架,模式集合以及测试、部署大规模新算法的现成模块。这本书是一张快车票,让你的机器学习算法运行在复杂的分布式计算框架上。
若是你正在领导一个产品团队或者初创公司想利用机器学习创造竞争优点,这本书也适合你。经过真实世界的例子,这本书能够启发你不少技术可能有多种实现方式的想法。它能够帮助你充满斗志的技术团队成员直接跳到很划算的实现能处理大量数据的应用,而在放在之前必须组织大量的技术资源才能够实现。
最后,你可能想知道怎么读“Mahout” – 这是一个经常使用的英式,它与“trout”押韵。这是一个北印度语的单词,指的是驱使大象的人,为了解释这个词,下面介绍一段关于它的历史。Mahout项 目开始于2008年,做为ApacheLucene的子项目,Apache Lucene项目是你们熟知的开源搜索引擎。Lucene提供了搜索、文本挖掘和信息检索的高级实现。在计算机科学领域,这些概念和机器学习技术近似,像 聚类、分类。因此,Lucene贡献者的一部分机器学习相关工做被剥离进入子项目。不久后,Mahout吸取进“Taste”开源协同过滤的项目。
自2010.4月起,Mahout成为Apache的顶级项目。
Mahout的大量工做不仅是传统的实现这些算法,也实现将这些算法,让它们工做在hadoop之上。Hadoop的吉祥物是一头大象,这也解释了Mahout的工程名字。
图1.Mahout以及相关项目 (见附件)
Mahout孵化了至关多的技术和算法,不少都是在开发和实验阶段。在工程的早期阶段,有3个核心主题:协同过滤/推荐引擎、聚类和分类。这并非Mahout中全部内容,但倒是最显著、成熟的主题(在本书写做时),所以,这是本书的范围。
若是你读了以上内容,说明你已经对这3个系列的技术有潜在的兴趣。可是为以防万一,请继续阅读下面的内容。
1.2 推荐系统引擎
推荐引擎是目前咱们使用的机器学习技术中最容易识别的。你可能已经见过相关的服务或网页,基于历史行为推荐书、电影、文档。他们尝试推论出用户偏好,并标记出用户不知晓的、感兴趣的item:
对于Amazon和示例其余网站,经过这种聪明的交叉销售,推荐系统确实有具体的经济价值,同一家公司的报告指出推荐产品给用户可以带来8-12%的销售增加。
http://www.practicalecommerce.com/articles/1942-10-Questions-on-Product-Recommendations
1.3 聚类
Clustering turns up in less apparent but equally well-known contexts.(首句该如何翻译,哪位仁兄帮个忙?)
顾名思义,聚类技术尝试去将大量的拥有相同类似度的事物汇集到不一样的类中。聚类是在海量或者难于理解的数据集里发现层次和顺序,展示兴趣模式,或使得数据集容易被理解。
1.4 分类
分类技术用于决定一个事物是否是属于一种类型、类目,或者该事物是否是含有某些属性。一样地,分类无处不在,尽管更多的时候隐于幕后。
这些系统经过评估item的不少实例来学习,以推导出分类规则。这个日常的想法能够找到不少应用:
分类有助于判断一个新进入事物是否匹配先前发现的模式,也经常使用于分类行为或者模式。分类也可用来检测可疑的网络活动或欺诈。也可用于根据用户发信息断定表示失望或者满意。
1.5 扩展性
当有海量、高质量的数据输入时,这些技术都可以达到最佳效果。在一些状况下,这些技术不只要将海量数据做为输入,并且须要很快计算出结果。很快,这些因素使得可扩展性成为一个很大的问题。
依据一些粗略估计,Picasa在3年前可能已经拥有5亿张照片。这意味着天天须要分析数百万图片。分析一张图片并非一个大问题,尽管须要重复数百万次。可是,学习阶段须要亿万图片都提供相关信息 — 上了规模的计算,使用单机是不行的。
http://blogoscoped.com/archive/2007-03-12-n67.html
依据一个相似的分析,Google News大约天天有350万新文章。尽管数量并非很大,考虑到这些文章必须和目前其余文章同时聚类,为了及时响应计算时间须要在几分钟内。
Netflix为Netflix大奖发布的子集中包含1亿的打分。这只是适合竞赛的数据,据推测,Netflix实际上拥有的和必须用于建立推荐系统的整个数据远远大于这个这个量级。
http://archive.ics.uci.edu/ml/machine-learning-databases/netflix/
这些技术很是有必要应用于输入数据量很大的情形–由于很大,全部不适用于单机处理,甚至高配置的机器也不能够。因此,任何人实现这些技术都不能回避 可扩展性问题。这就是为何Mahout将可扩展性做为最高优先级,也是为什么本书关注可扩展性问题,别人所没有涉猎的一种方式,用于有效处理海量数据。
复杂的机器学习技术,上规模的应用,直到目前为止,只是一些大的、先进的技术公司在考虑。可是,今天计算能力已经比以前廉价,借助像Hadoop这 样的开源框架更方便。Mahout尝试经过使用hadoop提供优质、开源实现,可以在这个规模上解决问题,解决这类困惑,而且将其送到全部技术组织的手 中。
1.5.1 MapReduce and Hadoop
Mahout的一些部分使用了Apachehadoop工程,hadoop是一个开源的、基于java的MapReduce(http://labs.google.com/papers/mapreduce.html ) 实现。MapReduce是一种分布式计算框架,在Google内部使用。它是一种编程模式,开始听起来感受很奇怪,或者太简单了以致于很强大。MapReduce编程模式适用于输入是key-value键值对集合的问题。“map”函数将这些键值对转换为中间键值对。“Reduce”函数经过某 种方式将同一个中间键的值合并到一块儿并产出结果。实际上,不少问题能够设计成MapReduce问题,或者他们的一个系列。而且这种模式很是易于并行化实 现:全部的处理过程都是独立的,因此能够划分到不一样机器上去。这里再也不详细叙述MapReduce,hadoop提供的教程(http://hadoop.apache.org/common/docs/current/mapred_tutorial.html )。
Hadoop实现了MapReduce模式,这是一个不小的壮举,甚至让MapReduce像听起来那么简单。它管理输入数据、中间键值对、输 出数据的存储。这些数据多是海量的,须要在多台计算机上运行,而不仅是存储在某一台机器的本地。它管理不一样机器之间的划分、数据传输。它负责检测、恢复单个机器失败的状况。理解了有不少工做在幕后进行可以帮助你准备使用Hadoop的相对复杂性。不仅是将它做为类库添加到你的工程中,它包含不少模块,每个模块都有若干类库和独立的服务器进程,可能运行在几台机器上。基于Hadoop的操做处理不简单,但投入在可扩展的、分布式实现可让你在以后有很大的收获:由于你的数据可能成倍的增加,这种可扩展的性质对你的应用来讲是一种面向将来的方式。
稍后,本书将试着剪掉一些复杂性让你很快熟悉hadoop,基于这一点,你能够探索操做完整聚类的重点和细节,调整整个框架。由于这个须要大量计算能力的复杂框架变的愈来愈流行,因此一点都不奇怪,云计算已经开始提供hadoop相关的支持。例如Amazon提供的Elastic MapReduce(http://aws.amazon.com/elasticmapreduce/ )是一种管理Hadoop集群、提供计算能力、提供友好的接口的服务,可基于hadoop操做、监控大规模复杂任务。
1.6 安装Mahout
你须要安装不少工具,在你能“能够在家里玩”咱们后面章节提供的一些示例代码以前。咱们假设你已经熟悉Java开发。
Mahout以及和它相关的框架都是基于Java的,所以是平台无关的,你能够在任何一台安装了JVM的机器上使用他。有时候,咱们须要给出许 多不一样平台的示例和介绍,特别地,命令行模式在windows脚本和FreeBSD tcsh脚本有一些不一样。咱们使用命令行和与bash一块儿的句法,是一种类Unix平台的脚本。这是默认的在大部分Linux、 Mac OS X, 一些Unix变种和Cygwin(一种windows上的类Unix环境)。指望使用windows脚本的用户极可能不方便。尽管如此,本书下面的介绍列 表对你来讲应该能够很容易的理解。
1.6.1 Java和IDE
你若是以前作过任何Java开发的工做,你的我的电脑上已经装上Java了。注意Mahout须要使用Java6。若是有所疑虑,打开一个终端并键入java -version。若是报告不是以“1.6”开头,你仍须要安装Java6。
windows和Linux用户能在 http://java.sun.com 找 到Java 6 JVM。苹果公司为Mac OS X 10.5 和 10.6提供Java 6 JVM。若是发现Java 6没有被应用,在“/Applications/Utilities”打开“java perferences”。在这里能够选择Java 6做为默认选项。
大部分人能发如今IDE的帮助下,很是好编辑、编译和运行这些示例;因此强烈推荐你使用IDE。Eclipse(http://www.eclipse.org)是很是经常使用、免费的一款JavaIDE,安装配置Eclipse不在本书的讲解范围内,你能够花点时间去熟悉它。NetBeans (http://netbeans.org/) 也是一款经常使用开源IDE。 IntelliJ IDEA (http://www.jetbrains.com/idea/index.html)是一款强大的、流行的IDE,它有一个免费的社区版本。
例如,IDEA能从现有的Mavan模型中直接建立一个新工程;在建立新工程的时候,经过指定Mahout源代码的根目录,它将用一种友好的组 织方式自动配置、展现整个工程。例如,丢掉整本书的源代码 core/src/…,而后在IDE里面运行,只须要一次点击,依赖和编译的细节都会自动搞定。这证实了使用IDE比人工编译、运行容易不少。
1.6.2 安装Maven
和其余Apache工程同样,Mahout的构建、发布系统基于Maven(http://maven.apache.org)。Maven是一种命令行模式的管理代码,打包发布,生成文档,发布正式版本的工具。尽管它和Ant工具备一些相同之处,可是不一样。Ant是一种灵活的、低级别的脚本语言,Maven是一种高级别的工具,其目标倾向于发布管理。
由于Mahout使用maven,你应该先安装maven。Mac OS X用户会发现maven是默认安装,若是没有,安装苹果开发工具包。在命令行键入mvn –version。若是你能看到版本号,这个版本号最低2.2,那么能够继续进行。不然,你须要安装mavn的本地拷贝。
linux用户能够使用系统带有的包管理系统能够很是快的获取最近的maven版本。另外,标准方式是下载二进制版本,将其解压到/usr /local/maven,而后编辑bash配置文件~/.bashrc,添加一行exportPATH=/usr/local/maven/bin:$PATH。保证maven命令行一直有效。
若是你使用IDE,像Eclipse或者IntelliJ,他们已经集成了Maven。参考文档它的文档去了解如何将Maven整合。这将在IDE中使用Mahout变得简单一些,由于IDE能够根据那个Maven配置文件(pim.xml)配置、导入工程。
1.6.3 安装Mahout
Mahout仍在开发过程当中,这本书写的时候Mahout是0.4版本。能够在这里下载发布版本和其余介绍http://lucene.apache.org/mahout/releases.html 源文件能够解压到你电脑的任何地方。
由于Mahout的更新很频繁,有规律的进行漏洞修复、功能改进,在实际使用过程当中,使用最新发布版本的软件(或者使用svn上的最近的未发布 代码)可能对你的帮助更大,详见http://lucene.apache.org/mahout/developer-resources.html)。将来的发行版本应该向后兼容本书的示例。
一旦你从svn或者发布的归档文件中获取了源代码,在IDE中建立一个Mahout的新工程。这个对不一样IDE是过程不一样的,需根据如何完成建立的文档细节区别对待。使用IDE的Maven整合用工程根目录下的pom.xml导入Maven工程是很简单的。
一旦配置完成,你能够很容易的建立一个新的源代码文件夹来管理下面章节提到的样例代码。随着工程的配置完成,你应该能够透明的编译和运行代码,不须要再作其余工做。
1.6.4 安装hadoop
本书后面的一些行为,你须要在本机安装hadoop。你不须要一个集群去运行hadoop。配置hadoop不是很麻烦、繁琐。不重复这个过 程,咱们直接指导你在hadoop官网行获取hadoop 0.20.2版本的副本,http://hadoop.apache.org/common/releases.html,而后使用“伪分布式”方式安装 hadoop,详见http://hadoop.apache.org/common/docs/current/quickstart.html。
1.7 总结
Mahout是一个年轻的、开源的、可扩展的,Apache的机器学习库,本书是一本使用Mahout中的机器学习算法解决现实问题的使用指南。尤为是,你能够很快的探索推荐引擎、聚类、分类。若是你是一个机器学习领域的研究者,正在寻找一个实用指导、又或者你是这个领域的开发者,想从其余从 业者处快速学习实用方法,本书是很是适合你的。
这些技术不只仅是路论:咱们已经注意到不少知名的推荐引擎、聚类、分类的样例在现实世界中已经在应用:电子商务、邮件、视频、图片,更涉及大规模的机器学习算法。这些技术已经用来解决现实问题,甚至为企业产生了价值 — 这些如今在Mahout中都是能够触及的。
咱们已经注意到不少时候这些技术时常伴随着海量的数据 — 可扩展性是这个领域特别须要持续关注的。咱们首先来看一下MapReduce和hadoop,以及他们如何为Mahout提供可扩展支持。
由于这是一本动手实践的、实用书籍,咱们立刻开始使用Mahout。此刻,你应该已经安装好了Mahout须要的工具而且立刻开始行动。由于这本书以实用为主,因此将这些开幕词收起来去见识一下Mahout的代码吧。继续读下去。
第2章 推荐系统简介
本章包含如下内容:
咱们天天都会对喜欢的、不喜欢的、甚至不关心的事情有不少观点。这些事情每每发生的不知不觉。你在收音机上听歌,由于它容易记住或者由于听起来可怕而关注它 — 又或者根本不去关注它。一样的事情有可能发生在T恤衫,色拉,发型,滑雪胜地,面孔,电视节目。
尽管人们的爱好差别很大,但他们仍然遵循某种模式。人们倾向于喜欢一些事物,这些事物相似于他们本身喜欢的其余事物。由于我喜欢培根-生菜-西 红柿三明治,你可能猜到我可能也喜欢总汇三明治,相似于前者的带有火鸡肉的三明治。另外,人们倾向于喜欢兴趣和他们类似的人所喜欢的事物。当一个朋友进入设计学校,发现几乎周围全部同窗都用一个苹果电脑 — 不用吃惊,他已是一个终生的苹果用户。
这些模式能够用来预测喜爱与否。若是将一个陌生人带到你面前并问你,她是否喜欢指环王三部曲,你只能胡乱猜想了。可是,若是她告诉咱们她喜欢头 两部指环王,若是她不喜欢第3部,你会感到震惊。另外一种状况,若是她说讨厌指环或者问“什么王?”,你能够准确的猜想她对指环王不感兴趣。
推荐系统是关于这些预测偏好模型的系统,而且使用他们为你发现新的、趁心的事物。
2.1 推荐系统是什么
你由于某种缘由从书架上拿起这本书。可能你看到它临近其余的你熟知的书,发现他们是有用的,想到书店是由于喜欢那些书的人也会喜欢这本书才把他们放到一块儿。也可能你看到这本书在你同事的书架上,你和这个同事常常分享机器学习方面的知识,或者他直接将这本书推荐给你。
后面的章节探索了人们实现推荐系统的不少方法,发现新事物,固然有这些过程在Mahout软件中是如何实现的。咱们已经提到一些策略:为了发现你喜欢的items,你可能去寻找有相同兴趣的人。另外一方面,你能够由其余人的明显偏好计算出相似你喜欢的items的其余items。这描述了两大类推 荐系统算法:“user-based”和“item-based”推荐系统。
2.1.1 协同过滤 vs 基于内容的推荐
严格的讲,上面章节提到例子是“协同过滤” — 仅仅基于user和item关系的生产推荐系统。这些技术不须要item本身的属性信息。在某种程度上,这是一个优势,该推荐系统框架不须要关心“item”是书、主题公园、花、甚至人,由于他们的任何属性都没有做为输入数据。
有不少其余的方法基于item的属性,通常被称之为“基于内容”的推荐技术。例如,若是一个朋友推荐一本书给你,由于这是一本Manning出版的书,这个朋友喜欢其余Manning的书,那么你的这个朋友在作相似于基于内容推荐的事情。这种想法基于书籍的属性:出版社。Mahout推荐框架没 有直接实现这些技术,尽管它提供一些方法将item的属性信息添加到计算中。基于这些,技术上称前面的方法为协同过滤框架。
这些技术没有没什么问题;正相反,他们工做的很好。他们是特定领域的方法,可能很难有效地将他们整理到一个框架中。为了创建一个基于内容的图书 推荐系统,咱们须要决定书籍的哪些属性对推荐系统是有意义的、做用多少程度 — 页数、做者、出版社、颜色、字体。可是这些知识不能简单的应用于别的领域;像图书推荐的方法对披萨配料推荐是没什么帮助的。
基于这个缘由,Mahout没有过多涉及这种类型的推荐。能够将这些想法融入进来,但首要任务是Mahout提供些什么。其中的一个样例将在下 一个章节中讲解,在那里你将创建一个约会网站的推荐引擎。在介绍完Mahout基于协同过滤推荐的实现后,你有机会探索它和基于内容的推荐之间关系的细 节。
2.1.2 推荐系统成为主流
如今,不少人已经看到了推荐系统在现实网站上的实现,像Amazon或者Netflix:基于浏览和交易历史,页面将产生一个认为对你有吸引力 的商品列表。这类推荐引擎在上世纪九十年代已经出现,但直到如今它仍然是使用大型计算机的专门研究者的领域。由于这些技术已经变动加主流,对它们的需求在增长,开源实现的提供也是同样。随着理解的深刻和计算资源愈来愈廉价,推荐引擎变得愈来愈容易接近和普遍使用。
实际上,推荐技术不仅是为用户推荐DVD相似的东西。这种方法很是通用,能够用来评估不少事物之间的关系的强弱。
在社区网络中,一个推荐系统能够为用户推荐用户。
2.2 运行你的第一个推荐引擎
Mahout包含了一个推荐引擎 — 有不少类型,实际上都是源于传统的user-based和item-based推荐系统。它还包含了基于“slope-one”技术的实现,一个新的、有 效的方法。你将会找到不少实验性的、初步的的SVD(singular value decomposition)实现。下面的章节将从新看Mahout的内容。在这些章节中,你将看到数据展现、浏览可用的推荐算法,评价推荐系统的有效 性,针对特殊问题协调和定制推荐系统,最后看一下分布式计算。
2.2.1 建立输入数据
为了探索Mahout中的推荐系统,最好从一个很小的示例入手。推荐系统的输入是必要的 — 这些数据是推荐的基础。由于很是熟悉的推荐系统引擎将item推荐给user,很容易的认为偏好是user和item之间的联系 — 尽管前面提到了user和item能够是任何事物。偏好包含了一个user ID和一个item ID,一般状况下,一个数值表明了user对item偏好的强度。Mahout中ID都是数值,其实是整数。偏好值能够是任何值,值越大表明这正向偏好 越大。例如,这些值多是1到5的打分,user将1给于他不喜欢的,5给他很喜欢的。
建立一个文本文件包含用户数据,命名为“1”到“5”,他们对四本书的偏好,简单的称之为“101”到“104”。在现实状况中,这些多是公 司数据库中消费者ID和产品ID;Mahout并不须要user和item的ID必定为数值类型。使用下面的格式,生成文件intro.csv。
1,101,5.0
1,102,3.0
1,103,2.5
2,101,2.0
2,102,2.5
2,103,5.0
2,104,2.0
3,101,2.5
3,104,4.0
3,105,4.5
3,107,5.0
4,101,5.0
4,103,3.0
4,104,4.5
4,106,4.0
5,101,4.0
5,102,3.0
5,103,2.0
5,104,4.0
5,105,3.5
5,106,4.0
通过一些学习以后,趋势就显现出来了。用户1和用户5具备相同的兴趣。他们都喜欢101这本书,对102的喜欢弱一些,对103的喜欢更弱。同理,用户1和4具备相同的兴趣,他们都喜欢101和103,没有信息显示用户4喜欢102。另外一方面,用户1和用户2的兴趣好像正好相反,用户1喜欢 101,但用户2讨厌101,用户1喜欢103而用户2正好相反。用户1和3的交集不多,只有101这本书显示了他们的兴趣。看图2.1可能显现了 user和item之间的关系,多是正的也多是负的。
2.2.2 建立推荐系统
那么你应该给用户1推荐哪本书?不是101, 102或者103,由于用户已经知道本身对他们感兴趣,推荐系统须要发现新的事物。直觉告诉咱们,用户四、5与用户1相似,因此推荐一些用户4和5喜欢的 书籍给用户1多是不错的。这样使得10四、105和106成为可能的推荐。总体上看,104是最有可能的一个推荐,这基于item 104的4.5和4.0的偏好打分。如今运行下面的代码:
Listing 2.2 a simple user-based recommender program withmahout 代码
A 加载数据文件
B 建立推荐系统引擎Createthe recommender engine
C 对user1, 推荐一个item
为了简洁,后面许多其余章节的示例中,代码列表将省略imports、类声明、方法声明,只是重复程序语句。为展现很好的展现各个模块之间的关系,请看图2.2。并非Mahout中全部的推荐都是这样的,但这幅图能够给你一个样例的逻辑的初步印象。
接下来两章,在更细节的讨论这些模块以前,咱们能够总结一下每一个模块所扮演的角色。DataModel存储了全部的偏好信息,提供了对user 和item信息的访问。UserSimiliarity提供了两个用户如何类似的概念,这可能基于不少可能的矩阵和计算之一。 UserNeighborhood定义了一个给定用户的用户组的概念。最终,一个推荐系统将这些模块组合在一块儿将items推荐给users和相关功能。
2.2.3 分析输出
使用你细化的IDE编译运行,运行程序的输出应该是:RecommendedItem[item:104,value:4.257081]
请求一个推荐结果并获得一个。推荐系统引擎将书104推荐给用户1。甚至,这样作是由于推荐系统引擎将用户1对书104的偏好是4.3,这是全部推荐结果的最高打分。
这个结果并不算坏。107没有出现,本应该也是能够推荐的,但它只是和另外一个具备不一样爱好的user相关联。选104而不是106,由于104的打分高一些。还有,输出结果包含了一个用户1喜欢104的评估值 — 是介于用户4和5所表示的介于4.0和4.5的一个值。
直接看数据正确的结果并不明显,可是推荐系统引擎推荐了一个得体的结果。若是对从这个简单程序给出的有用并不明显的结果感到有一种愉快的刺痛,那么机器学习的世界是适合你的。
小数据集、产生推荐结果是一件微不足道的事情。现实中,数据集很大,而且噪声数据不少。例如,想象一个新闻网站推荐新闻给用户。偏好从文章的点 击中获取。可是,这里面的不少点击都是伪造的 — 可能不少读者点击一篇文章但他不必定喜欢它,或者点错了。可能不少点击都是在未登陆的时候发生的,不能将其关联到一个用户。想象一下数据集有多大,多是每个月几十亿的点击量。
要从数据集产生正确的推荐结果并快速计算出是一件不通常的事情。稍后咱们将展现工具Mahout如何解决这些问题。他将展现标准方法如何产生差的推荐结果或者占用了大量的cpu和内存时间,如何配置Mahout以提高性能。
2.3 评价推荐系统
推荐系统引擎是一个工具,一种回答问题的手段,“对用户来说什么是最好的推荐?”,在研究回答的前先研究一下这个问题。一个好的推荐的准确含义是什么?如何知道推荐系统是如何生成推荐的?下面的章节将探索推荐系统的评价,在寻找特定推荐系统时,这将是一个有用的工具。
最好的推荐系统是心理学的范畴,有人在你作事情以前知道确切的知道你尚未看过的、或者没有任何现象说明你喜欢的一些item,以及你对这些item的喜欢程度。
大部分的推荐引擎经过给item评价打分来实现。因此,评价推荐引擎的一种方式是评价它的评估偏好值的质量 — 评价评估偏好和实际偏好的匹配度。
2.3.1 训练集和打分
“真实偏好”并不充分,没有人会知道你未来是否会喜欢一些新的item。推荐引擎能够经过设置一部分真实数据做为测试数据。这些测试数据偏好在训练集中并不展现偏好值 — 要求推荐系统对这些缺乏偏好值的数据做出评估,并比较和实际值的差距。
对于推荐系统产生一系列打分是很简单的。例如,计算评估值和实际值之间的平均距离,在这种方法下,分值越低越好。0.0表示很是好的评估 — 评估值和实际值根本没有差距。
均方根(root-mean-square)也是一种方法,也是分值越低越好。
上面的表中展现了实际偏好度和评估偏好度集合的不一样值,以及如何将它们转化为打分。均方根能比较重的处罚距离远的,例如item2,这是基于某种考虑在内的。由于平均距离容易理解,接下来的示例将使用它做为评估方法。
2.3.1 运行RecommenderEvaluator
下面是代码示例:
大部分的操做发生在evaluate()这个方法中。内部,RecommenderEvaluator将数据划分为训练集和测试集,建立一个新的训练DataModel和推荐引擎测试,比价评估结果和实际结果。
注意,没有将Recommender传给方法,这是由于在其内部,将基于建立的训练集的DataModel建立一个Recommender。因此调用者必须提供一个RecommenderBuilder对象用于从DataModel建立Recommender。
2.3.3 评估结果
程序打印出了评估结果:一个代表推荐系统表现如何的打分。在这种状况下你能看到很简单的1.0。尽管评价器内部有不少随机方法去选择测试数据,结果多是一致的由于RandomUtils.useTestSeed()的使用,每次选取的随机数都同样。这只用于示例、单元测试来保证重复的结果。不要在真是数据上用它。
AverageAbsoluteDifferenceRecommenderEvaluator
基于AverageAbsoluteDifferenceRecommenderEvaluator实现,获得的这个值是什么含义?1.0意味着,平均意义上,推荐系统评估偏好和实际偏好的的距离是1.0.
1.0早1-5规模上并不大,可是咱们的数据太少。若是数据集被随机划分结果可能不同,所以训练、测试数据集可能每次跑都不同。
这种技术能够应用于任何Recommender和DataModel。使用均方根打分的实现类RMSRecommenderEvaluator
替代AverageAbsoluteDifferenceRecommenderEvaluator。
evaluate()的null参数是DataModelBuilder的实例,用于控制训练DataModel是如何从训练数据上创建的。正常状况下默认就好,若是须要,能够使用特别实现的DataModel。DataModelBuilder用于将DataModel注入评价过程当中。
参数1.0表示使用整个数据集的比例。这样用于产生一个很快的、可能精度低一些的评价方式。例如,0.1可能意味着用数据集的10%,忽略其余90%。这对于快速检测到Recommender的细微变化是很是有用的。
2.4 评估准确率和召回率
借用更广泛的见解,咱们接收经典的信息检索矩阵去评价推荐系统:准确率和召回率。这些是用于搜索引擎的术语,经过query从众多可能结果中返回最好结果集。
一个搜索引擎不该该在靠前的结果中返回不相关的搜索结果,即便他致力于获得尽量多的相关结果。”准确率”是指在靠前的结果中相关结果所占的比 例,固然这种相关是某种程度上咱们定义的相关。”precisionat 10″应该是从前10个结果中判断获得的准确率。“召回率”靠前的结果中相关结果占的比例。看图2.3能够有一些直观的概念。
这些术语也能够应用到推荐系统中:准确率是靠前的推荐中好的推荐所占的比例,召回率是指出如今靠前推荐中好的推荐占整个好的推荐的比例。
2.4.1 运行RecommenderIRStatsEvaluator
Mahout提供了很是简单的方式为推荐系统计算结果。
2.5 评价GroupLen数据集
有了这些工具在手,咱们不只能够考虑速度,还要考虑推荐系统的效率。尽管大量数据集的例子还在几章之后,小数据集上评价性能已成为可能。
2.5.1 抽取推荐系统输入
GroupLens (http://grouplens.org/)是一个研究型的项目。提供了不少不一样大小的数据集。每一个都是用户对电影打分的真实数据。这是几个大的真实可用数据集之一,更多的将会在本书后续探寻。从GroupLens网站上下载“100K data set”,http://www.grouplens.org/node/73.解压下载文件,在解压后后,有一个叫ua.base的文件。该件tab分割user IDs, itemIDs, ratings(偏好值)和其余信息。
这个文件能使用吗?Tabs, 不是逗号,分隔字段,在每行结尾还有一个额外的字段。答案是确定的。该文件能够相似FileDataModel的读取。回到前面列表2.3,试着用 ua.base的路径代替小文件路径。从新跑一遍数据。这时,评估可能须要几分钟,由于数据量是100k。
最后,你应该获得一个大约0.9的值。这不算坏,尽管值几乎分布在1-5区间内,听起来还不错。可能特殊的推荐系统对这种类型的数据来说是不彻底的?
2.5.2 其余推荐系统实验
在这个数据集上测试“slope-one” ,一个简单的算法,在后面的章节中会讲到。很容易替换RecommenderBuilder,使用org.apache.mahout.cf.taste.impl.recommender.slopeone.SlopeOneRecommeder, 像这样:
运行评价方法。你应该发现它很快,获得一个大约是0.748的值。正朝好的方向发展。
这并不能说明slope-one算法老是很快、很好。在给定数据集上,每个算法都有本身的特性和属性,这些属性很难去检测出来。例如,slope-one算法运行时可以很快的计算推荐过程,可是它须要在计算前须要花费很大一部分时间构建内部数据结构。基于用户的推荐引擎,可以在其余数据集上拥有很快的计算速度和更高的准确度,咱们将在第四章探索各类算法的优势。
2.6 总结
在这一章咱们介绍了推荐引擎的思想。咱们建立了一些简单的Mahout Recommender的输入,运行一个简单计算,而后输出结果。
而后,咱们花时间介绍了推荐引擎系统的数据结果的质量评价,由于接下来的章节会频繁用到。这一章包含了评价推荐引擎的准确性,像传统的准确性和召回率。最后,咱们尝试去评价GroupLens的真实数据集,观察如何将评价结果用于推荐引擎的性能提高上。
在咱们继续详细学推荐引擎以前,须要花一些时间去了解另外一个Mahout中推荐系统的基本概念:数据表示。接下来一章会着重讲这一点。
这章主要讲述:
。Mahout如何展示recommender data
。DataModel的实现及其用法
。没有评分数据
Recommendations的质量主要是由数据的数量和质量决定的。“无用输出,无用输入” 在这里是最真实的。一样,推荐器算法都是集中数据,运行的性能主要受数据的数量和展示的影响。这一章介绍Mahout的一些关键class,和访问推荐器相关的数据。
mahoutin action 3.1 Preference对象
一个推荐引擎的输入数据是评分数据:它喜欢什么以及多少。因此,Mahout recommenders的输入数据是一组简单的“userID”,“itemID”,和“评分数据”元组,固然,这是一个大的集合。评分数据有时候会被省略。
3.1.1Preference对象
Preference 是一个最基础的概念,它表现一个单一的userID,itemID和一个评分数据。这个对象表现为一个用户对一个项目的打分。Preference是一个 接口,一般使用的实现类为GenericPreference。例如:建立一条记录,user(123),对item(456)的打分是3.0: newGenericPreference(123, 456, 3.0f)。
一组Preferences如何表现?若是你给出了一个合 理的答案,如Collection<Preference>或者 Preference[],大部分状况下,在MahoutAPIs中不是这样实现的。Collections和arrays对处理海量Preference对象是无效的。若是你在Java中从未研究过上面的对 象,你可能会感到困惑!
单个的GenericPreference包含20个字节的有用数据:一个8字节的user ID(Java long),8字节的item ID(long),4字节的分值(float)。这个对象的存在使GenericPreference包含的字节有惊人的增加:28个字节!这个变化依赖的是JVM的实现;这个数字是从苹果Mac OS X 10.6的64位Java 6 VM 获得的。因为上面的对象和其余线性问题,对这个对象来讲,28个字节中包括8字节的参考值,另外20个字节的空格,在对象自身的表现内。因为上面的现象,所以一个GenericPreference对象已经比它须要多消耗了140%的存储。
为何这么作?在recommender算法中,都须要全部评分数据的集合,这些评分数据是与一个用户或一个项目联系在一块儿的。在这样一个集合里,user ID或者item ID与全部好像多余的Preference对象将会是配套的。
3.1.2PreferenceArray和实现
进 入PreferenceArray,这个接口的实现表现为一个具备相似与数组的API的分值的集合。例 如,GenericUserPreferenceArray表现为一个用户的全部打分.它在内部包括一个单一的user ID,一系列的item IDs,一系列的评分值。在一个用户的全部打分中,须要占用12个字节的内存(一个8字节的item ID和一个4字节的评分值)。把它与须要一个完整的Preference项目的大约48个字节相比较。这个4字节内存,包括对齐这个特殊的实现,
但它也提供了小的性能提高,更小的对象必须被垃圾回收器分配和检查。比较图3.1 and 3.2去理解这些保存是如何完成的。
图3.1效率较低的评分值的表现,利用一系列的Preference对象。灰色的区域表明上面的对象。白色的区域是数据,它包括引用对象。
图3.2利用GenericUserPreferenceArray更有效的表现
下面的代码表现一个PreferenceArray的典型的构造和使用
列表3.1在一个PreferenceArray中设置评分值
Java代码:
PreferenceArray user1Prefs = newGenericUserPreferenceArray(2);
user1Prefs.setUserID(0, 1L); //A
user1Prefs.setItemID(0, 101L);
user1Prefs.setValue(0, 2.0f); //B
user1Prefs.setItemID(1, 102L);
user1Prefs.setValue(1, 3.0f); //C
Preference pref = user1Prefs.get(1); //D
PreferenceArray user1Prefs = newGenericUserPreferenceArray(2);
user1Prefs.setUserID(0, 1L); //A
user1Prefs.setItemID(0, 101L);
user1Prefs.setValue(0, 2.0f); //B
user1Prefs.setItemID(1, 102L);
user1Prefs.setValue(1, 3.0f); //C
Preference pref = user1Prefs.get(1); //D
A 为全部打分设置user ID
B User 1当前为item 101的打分2.0
C User 1为item 102的打分3.0
D Item 102的一个Preference实现
一样这里存在一个称为GenericItemPreferenceArray的实现,它内部的全部分值,与item关联而不是与user关联。它的目的和用法都是彻底相似的。
mahoutin action 3.2 加速汇集
很是高兴的是,Mahout已经从新创造了“java数组对象”。这只是万里长征的第一步。咱们说起到规模是重要的吗?可能,你已经被说服,咱们将会面对处理巨大数量的数据,和不寻常响应。
这 个reduced的内存需求,由PreferenceArray和它的实现,带来的复杂性是值得的。削减内存需求的百分之七十五不仅是节约一对M字节。在 一个合理的规模上,它节约了10分之一G内存。这多是在你现存的硬盘上是否装配之间的不一样。这是是否必须投资大量的RAM和可能的一个新的64-bit 系统之间的不一样。那是一个小的,但真正节能的技术,很是重要。
3.2.1FastByIDMap 和 FastIDSet
当 你听到Mahout recommenders大量的使用如map和set的典型的数据结构时将不会感到奇怪,可是不要使用如TreeSet和HashMap的普通的Java实现。相反,遍历这个实现和API你将会找到FastByIDMap和FastIDSet。它们是像Map和set同样的程序,可是是被明确的详细说明,并只提供Mahout recommenders须要的程序。它们减小内存占用而不是在性能上显著的增长。
这里没有一个像java中的Collections。可是,它们在一个大范围的环境内,为有效的目的而精心设计。它们不能对将来的使用作出更多的假设。Mahout的须要对可获得的用法有更加特殊,更强的假设。主要不一样是:
。如同HashMap,FastByIDMap 是 hash-based。它使用线性探索而不是分离连接来处理hash collisions。这避免了一个额外的Map.Entry对象的每一个入口的须要;如咱们所讨论的,Objects占用了使人惊奇的内存数量。
。Keys和members在Mahout recommenders中老是长的基元,而在objects中则不是。使用长的keys节约内存并提升性能。
。Set的实现不是使用下面的一个Map来实现的。
。FastByIDMap能够像一个cache同样起做用,由于它有一个“maximum size”的概念;超过这个尺寸,当增长了新的entries时,infrequently-used entries将会被删除。
存 储的不一样是有意义的:与HashSet 的84个字节相比,FastIDSet平均每一个member须要大约14个字节。与HashMap 的每一个入口的84个字节再次比较,FastByIDMap每一个入口占用28个字节。这显示当一我的对用法作了更强的假设时,有意义的改善是可能的:主要在 内存需求上。考虑到为recommender系统提供的讨论中的数据量,这些习惯的实现不只仅证实了它本身。因此,这些类用在哪里?
mahoutin action 3.3 内存中的DataModel
这 是个抽象概念,在Mahout中,recommender的输入数据是DataModel。DataModel的实现为各类推荐器算法须要的数据提供了有效的使用。例如,一个DataModel能够在输入数据中,提供一个包括全部userIDs的列表,或提供与一个item相关联的全部分值,或者提供一个为一系列item IDs打分的全部用户的列表。咱们将会集中研究一些highlights;一个关于DataModel的API的更详细的描述,能够经过在线文档中找到。
3.3.1GenericDataModel
这个咱们先来看一下,最简单 的实现(在内存中实现),GenericDataModel。当你想用编程的方法,而不是基于一个现存的外部数据资源。例如一个文件或相关数据库在内存中建立你的数据表现时,这是很是合适的。它只是以这种形式把分值看成输入数据,这个形式就是一个FastByIDMap映射user IDs到有这些用户的数据的PreferenceArrays上。
列表3.2 基于GenericDataModel,定义输入数据
Java代码
FastByIDMap<PreferenceArray> preferences =
new FastByIDMap<PreferenceArray>();
PreferenceArray prefsForUser1 = new GenericUserPreferenceArray(10);//A
prefsForUser1.setUserID(0, 1L);
prefsForUser1.setItemID(0, 101L); //B
prefsForUser1.setValue(0, 3.0f); //B
prefsForUser1.setItemID(1, 102L);
prefsForUser1.setValue(1, 4.5f);
… (8 more)
preferences.put(1L, prefsForUser1);// C
DataModel model = new GenericDataModel(preferences); //D
FastByIDMap<PreferenceArray> preferences =
new FastByIDMap<PreferenceArray>();
PreferenceArray prefsForUser1 = new GenericUserPreferenceArray(10); //A
prefsForUser1.setUserID(0, 1L);
prefsForUser1.setItemID(0, 101L); //B
prefsForUser1.setValue(0, 3.0f); //B
prefsForUser1.setItemID(1, 102L);
prefsForUser1.setValue(1, 4.5f);
… (8 more)
preferences.put(1L, prefsForUser1);// C
DataModel model = new GenericDataModel(preferences); //D
A为user 1创建PreferenceArray
B添加第一个preference,在刚刚建立的10中
C把user 1的preference添加到输入数据上
D建立DataModel
一 个GenericDataModel使用多少内存?储存的分值的数目占内存占用的绝对优点。经过一些经验揭示,每一preference占用28个字节的Java heap space 。它包括全部的数据和其余次要数据结构--如指数。若是你喜欢你也能够尝试一下;下载一个GenericDataModel,调用 System.gc() ,几回后,比较Runtime.totalMemory()和Runtime.freeMemory()的结构。这是未加工过的,但应该能够给出一个合理 的估计,这个估计就是数据占有多少内存。
3.3.2 基于文件的数据
一般咱们不会直接地使用GenericDataModel,而是可能使用FileDataModel: FileDataModel从一个文件中读取数据,并能够在内存中储存做为结果的分值数据,从而转化为GenericDataModel。
几 乎任何一个合理的文件都将会这么作。咱们在第一节里已经看到了一个这样文件的例子,在这节里,咱们创造了一个简单的用逗号分割数据的文件,在这个文件里, 每一行都包含一个数据:user ID,item ID,分值。使用Tab分割的文件也一样这么作。若是它们的名字各自以“.zip” 或“.gz”为后缀,使用对应的zip和gzip解压。在压缩格式储存这一数据是一个好想法,由于它是巨大的,而且被压缩好的。
3.3.3Refreshable组件
有时推荐引擎中呈现偏好值为空的记录。它表明了用户和项目是接洽关系的,然则并无发挥解析出接洽关系程度。举了例子,一个消息网站按 照用户已浏览内容为用户推荐消息。“已浏览”使一个用户和一个项目产生了接洽关系,然而这是独一能够或许获取的信息。通常网站也不会让用户去给文章作个排序,更不会让用户再作除了浏览以外的其余什么事了。因此咱们仅仅知道用户和那些文章接洽关系了,而再也没有其余的内容了。
面对如许的景象,咱们别无选择。这里不会有偏好值。后续几章将会依然供给处理惩罚如此景象的技巧和建议。然而有时咱们忽视掉偏好值也何尝不是坏事,只要景象需要。
丢掉用户和项目之间的接洽很轻易,或者说咱们能够直接忽视偏好值就能够办到。好比,你宁肯推敲有没有看过一个电影,也不愿去给一个电影 打分。换句话说,咱们宁可把数据改成“用户1和项目3有关系”,也不愿意写成“用户1喜爱项目103的程度为4.5”。下面是一个示意图,来申明两者之间 的差异:
图3.4 带偏好值的数据(左)与布尔偏好数据(有)的差异
用Mahout的说话,没有不带偏好值的记录就是布尔偏好,由于一个接洽关系只有两种值:要么有接洽关系,要么没接洽关系。这不表明偏好只有两个值:是和否,而是有三个:喜爱、不喜爱、不知道。
为什么有时会忽视偏好值?由于会有如许的景象,用户喜爱或者不喜爱一个项目标程度相对一致,至少与那些和用户没有接洽关系的项目比拟。还 记得那个例子吗?一个家伙不喜爱拉赫玛尼诺夫(Rachmaninoff),固然世上有不少曲子他没有听过(好比灭亡金属音乐(Norwegiandeath metal))。如许咱们只得到了他与这个做家的一个接洽关系,刚巧他又喜爱另外一个做家布拉姆斯,而后他把拉赫玛尼诺夫标为1,把布拉姆斯标为5,和其他 未知做家比拟,如许的偏好值是没有什么意义的,认为两者在某种程度上是对等的。因此咱们索性不要这个偏好值,仅仅是喜爱、不喜爱、不知道或者说未知的关系。
你可能会说这都是用户的错。莫非他就不克不及为拉赫玛尼诺夫打4分而为灭亡金属打1分。也允许以,但你仍是认了吧!由于事实上推荐所须 要输入的数据是很难判定的。你或许还要提出否决,当然对于全部流派均可以如许去推理,然则当你要向他推荐古典做曲家时该根据哪些数据呢?没错,在某范畴中的好的解决计齐截般不会公开出来。
抛去偏好值能够很大程度上化简数据表达,固然也会提拔机能、占用更少的内存。像看我以前懂得的,在Mahout中需要用4个字节的浮点 数去存储偏好值,至少如果没有偏好值也就意味着咱们每一条会罕用4个字节。在内存方面的测试中也确切均匀每笔记录都削减了4个字节到24字节了。
这个测试用的是GenericDataModel的双胞胎兄弟GenericBooleanPrefDataModel。它看上去是一个内存版的实现,然则它没有偏好值。事实上,它仅仅用FastIDSets去存储一个用户和项目标接洽关系。例如,只为每一个用户存储和他接洽关系的全部项目ID,这里不会再呈现偏好值。
由于GenericBooleanPrefDataModel也是DataModel对象,因此它彻底能够直接庖代 GenericDataModel。一些数据模型的办法在这种实现下会变得快速高效,好比:getItemIDsForUser(),由于该办法在它里面取项目ID是现成的。某些办法也会变慢,好比:getPreferencesFromUser(),由于它的实现没有应用 PreferenceArrays,而且必须实现如下该办法。
你可能会好奇getPreferenceValue()在这里能够返回什么?由于这里不是没有偏好值吗?你调用该办法并不会抛出 UnsupportedOperationException的异常,它会恒定的返回一个子虚值1.0。这一点值得重视,每一个组件都邑依附于一个偏好值, 它们必须从DataModel对象中获取一个。这些捏造而且固定的值也会产生一些奥妙的题目。
让咱们在文章最后来调查一下GroupLens例子的成果。下面是应用了GenericBooleanPrefDataModel的代码片断:
清单 3.7 用布尔偏好值建立和评估一个推荐器
DataModel model = newGenericBooleanPrefDataModel(
GenericBooleanPrefDataModel.toDataMap(
new FileDataModel(newFile("ua.base")))); A
RecommenderEvaluator evaluator =
newAverageAbsoluteDifferenceRecommenderEvaluator();
RecommenderBuilder recommenderBuilder = newRecommenderBuilder() {
public Recommender buildRecommender(DataModel model)
throws TasteException {
UserSimilarity similarity = newPearsonCorrelationSimilarity(model);
UserNeighborhood neighborhood =
new NearestNUserNeighborhood(10, similarity,model);
return
new GenericUserBasedRecommender(model, neighborhood,similarity);
}
};
DataModelBuilder modelBuilder = newDataModelBuilder() {
public DataModel buildDataModel(
FastByIDMap<PreferenceArray>trainingData) {
return new GenericBooleanPrefDataModel(
GenericBooleanPrefDataModel.toDataMap(trainingData)); B
}
};
double score = evaluator.evaluate(
recommenderBuilder,modelBuilder, model, 0.9, 1.0);
System.out.println(score);
A 基于雷同的数据,应用GenericBooleanPrefDataModel
B 建树一个GenericBooleanPrefDataModel
这里的转折是DataModelBuilder。它能够使评估法度为练习数据机关DataModel对象,而不是去机关一个 GenericDataModel对象。GenericBooleanPrefDataModel用一种稍微不合的体式格式去获取数据——用一些 FastIDSets而不是PreferenceArrays。而且它还供给了一个很便利的办法toDataMap()用来对两者进行转换。在进入下一末 节时,测验测验运行一下这个法度,他将不会很成功的履行完毕。
你会发明在PearsonCorrelationSimilarity的机关办法中抛出了 IllegalArgumentException。刚开端你可能感受很不成思议,GenericBooleanPrefDataModel莫非不也是 DataModel对象吗?它与GenericDataModel的独一差异不就是没有偏好值吗?
这个相似度怀抱对象EuclideanDistanceSimilarity拒绝在没有偏好值的景象下工做,由于如许产生的成果是无心义的。皮尔森相干系数(Pearson correlation)在两个数据集数据彻底反复、同样时就是没有意义的。在这里DataModel的偏好值所有为1.0,那么策画出来的欧几里得间隔 只能在一个点空间(1.0, 1.0, …, 1.0)中进行,如许是毫无心义的,由于全部的相似度都是0。
大致上讲,不是全部的实现均可以在一路很好的匹配在一路,甚至都实现自一个接口的对象也不成能彻底匹配。为懂得决这个当前题目,咱们须 要调换掉这个策画相似度的类。LogLikelihoodSimilarity就是一个好的选择,由于它不需要偏好值,咱们将即速评论辩论它。在法度顶用 它调换PearsonCorrelationSimilarity,这个成果就变成了0.0。很不错吧!这意味着它的成果正确了,不过这真的很好吗?
不幸的是,全部的偏好值都是1固然会致使全部的偏好相差为0了。这个测试自己没有什么意义,由于它将永远都是0。
然而,查准-召回评估仍是依然有效的,让咱们来试一下吧:
清单3.8 应用布尔数据评估查准率和召回率
DataModel model = newGenericBooleanPrefDataModel(
new FileDataModel(newFile("ua.base")));
RecommenderIRStatsEvaluator evaluator =
new GenericRecommenderIRStatsEvaluator();
RecommenderBuilder recommenderBuilder = newRecommenderBuilder() {
@Override
public Recommender buildRecommender(DataModel model) {
UserSimilarity similarity = newLogLikelihoodSimilarity(model);
UserNeighborhood neighborhood =
new NearestNUserNeighborhood(10, similarity,model);
return newGenericBooleanPrefUserBasedRecommender( model, neighborhood, similarity);
}
};
DataModelBuilder modelBuilder = newDataModelBuilder() {
@Override
public DataModel buildDataModel(FastByIDMap<PreferenceArray> trainingData) {
return new GenericBooleanPrefDataModel(
GenericBooleanPrefDataModel.toDataMap(trainingData));
}
};
IRStatistics stats = evaluator.evaluate(
recommenderBuilder,modelBuilder, model, null, 10,
GenericRecommenderIRStatsEvaluator.CHOOSE_THRESHOLD, 1.0);
System.out.println(stats.getPrecision());
System.out.println(stats.getRecall());
评估成果为查准率和召回率均为15.5%,这个成果并不睬想。这意味着推荐成果中6个只有1个是好的推荐,6个好的推荐中只推荐出了1个。
这引出了第三个题目,偏好值依然埋伏于GenericUserBasedRecommender对象之中。由于推荐成果遵照偏好值排序,而偏好值尽是1.0,因此如许的次序是彻底随机的。因此咱们引出GenericBooleanPrefUserBasedRecommender(是的,正如它名字同样,它能够办到)。它能够在推荐成果中产生一个颇有意义的排序。它为每一个项目接洽关系于其余相似的用户加权重,用户越相似,那么权重也会 越高。它没有供给一个加权均匀数。调换以后在运行代码,成果可能在18%,好了一点,但没有好太多。这种成果预示着推荐体系对于这些数据不是非常有效,我 们的目标不是要去批改它,仅仅是去看如安在Mahout中有效的安排如许带有“布尔偏好”的数据。
其余DataModel对象的布尔变种也是有的。FileDataModel在记录中没有偏好值的景象下内部会主动的应用一个 GenericBooleanPrefDataModel的对象。相似的,MySQLBooleanPrefDataModel适实用在数据库中无偏好值的景象。它与以前的对象彻底相似,而且它的实现能够充沛的哄骗数据库供给的某些捷径来提拔自身的机能。
最后,你如果好奇布尔型和非布尔型是否是能够混在一路处理惩罚,答案是否认的。在这种景象下,咱们更偏向于遵照存在偏好值的景象去向理 惩罚,由于毕竟成果有些偏好值是存在的。那些没有偏好值的记录可能或者应当能够经由过程某些手段揣摩出它的偏好值,甚至咱们能够吧均匀偏好值填进去当作一个占位符。
这一章咱们看到了数据在Mahout的推荐器中如何去表达、浮现。这里包含了Preference对象,酷似凑集实现的特别数组PreferenceArray以及FastByIDMap。这些特定定制的对象很大程度上削减了内存的消费。
再看看DataModel,它是推荐器输入数据的一种抽象封装。在FileDataModel读取完本地文件以后,GenericDataModel在内存中存储这些数据。JDBCDataModel用来接见数据库的数据,而且咱们还在MySQL上特意进行了测试。
最后咱们评论辩论了在无偏好值的景象下,这些模型该如何的变动。通常上述这些对象都邑用到,固然存储上会稍微少一些。咱们列举了一些标 准对象与该类数据不匹配的例子,如PearsonCorrelationSimilarity。最后经由过程检查题目的缘由地点而解决了题目,目标是为了 构建一个基于布尔偏好数据的推荐器。
本章概述:
分析维基百科上的一个大数据集
利用Hadoop和分布式计算产生推荐结果
伪分布式上存在的非分布式推荐
本书着眼于持续增加的数据集,从10条到100,000再到1千万再到1.7千万。不过这依然是中等大小的推荐系统所处理的 数据。本章依然放手一搏,处理了来自维基百科语料库中的1.3亿条数据,这些数据主要是以文章对文章的链接形式存在的。在这些数据集中,文章既充当了用 户,也充当了项目。这也显示了Mahout在特定情形下十分灵活的应用。
为知足演示目的,1.3亿的数据仍是可管理的。可是对于单机处理推荐过程仍是有一些困难的。这就须要使用一种新的推荐算法,经过Mahout基于的Mapreduce范式与Hadoop来实现分布式计算。
咱们首先要检测一下维基百科的数据来认识一下它对于分布式推荐计算意味着什么。你将会学习到如何在分布式的环境下设计一个推 荐器,由于这与非分布式的推荐计算有很大的不一样。你也将看到Mahout如何把以前的算法设计翻译成基于MapReduce和Hadoop的实现。最后, 你将运行一个完整的基于Hadoop的推荐Job程序。
咱们从分析维基的数据开始,可是很快咱们会发现因为问题规模而引发的问题。咱们将很快退后几步去深刻了解下分布式计算是如何执行的。
维基是一个由用户编写和维护的在线百科全书。据报道,在2010年它已经包含320万篇英文文章了。维基文章提取的开源项目(http://download.freebase.com/wex/)估计全部维基文章大概有42GB。基于互联网,维基文章能够相互连接。这些连接表明了某种兴趣。能够作个比方,一篇文章像是用户同样“喜欢”另外一篇文章做为其偏好的项目。
幸运的是咱们无需下载上述项目所提取的文章也不须要去分析出它们之间的连接。研究人员Henry Haselgrove已经在http://users.on.net/~henry/home/wikipedia.htm上发表了他所完成的提取信息。另外,还有一些深刻的提取,例如文章的讨论页、图片等等。这些数据采用数字ID而不是文章的标题,这样很是有好处,由于Mahout自己就是使用数字ID的。
在往下继续以前,先下载并解压links-simple-sorted.zip,其中包含5,706,070篇文档对 3,773,865篇不一样文档的130,160,392个连接。主要说明的是,这些数据中没有偏好值或者排名等级,这里只有文章与文章之间的关联关系。也 就是说,这属于一种“布尔偏好”。文章A连接了文章B,不能表明B对A也有连接。在这里,用户和项目是同样多的,因此不管是基于用户的算法仍是基于项目的算法无好坏之分。若是使用一个涉及类似度度量的算法而且不依赖于偏好值,那么LogLikelihoodSimilarity会比较合适。
直觉上这些数据具备什么意义?而且咱们指望得到什么样的推荐结果?一条从A到B的连接表示了B向A提供了一些相关参照信息。一个基于这些信息的推荐信息将会一些和A指向相同或类似的文章。这些推荐出来的文章被解释成它们没有被A指向却应该被A指向。推荐系统将揭示一些对A感兴 趣或者会偶然关联上的一些文章。
在处理这样大的数据时,一个非分布式的推荐引擎可能就搞不定了。单单这些数据就要消耗JVM堆空间2GB大小,再加上 Mahout程序所需空间,可能须要2.5GB。这已经超过了某些32位的机器的堆空间大小。也就是说,你须要一台64位的机器,今儿不换明儿也得换。再 因为推荐算法固有的时间复杂度,推荐系统须要超过一秒的时间去完成推荐任务,这对于现代Web实时应用来讲已是很是慢了。
若是咱们有足够多的硬盘,那么咱们能够搭建这样一个平台。可是总有一天,随着数据的日益增多,到了十亿或者更多,所需的堆空 间也达到了上限32GB呢?对了,也许有人会开始琢磨如何对数据降噪去减小数据的量,提升数据的精度。可是这并不能从根本上回避数据增加所带来的问题。
若是你的系统在处理数据规模上有限制的话,那么只能说你Out了。计算资源能够无限的增长;那么咱们要解决的问题是若是把这些计算资源整合在一块儿去协同的完成任务。你的收益和制做一个超级计算机(计算能力的提高)所需的成本是不成比例的,因此咱们应该想办法利用多个普通机器的 计算资源。对于那些单点无任何联系的机器,堆在一块儿只能是浪费电源,最有效利用他们的方式就是联合它们去为推荐系统效力。
这些维基数据的大小表明了一个基于Mahout的实时推荐系统所处理数据的上限。——这其实已经超过现代的标准了。对于这样的数据规模,咱们须要一个新的方法。
根据上面说明的缘由,咱们不得以才使用多个普通机器与代替一个高性能机器。一个公司或学术组织可能拥有不少未充分利用的普通 机器,这样这些机器额外的空闲资源就能够用来作推荐任务。另外有一些计算资源也能够经过云计算的提供商哪里获得,好比亚马逊EC2服务 (http://aws.amazon.com)。
图 6.1 分布式能够将一个数据规模很大的问题化简成不少小规模数据的问题,从而分配给较小的服务器上去计算。
分布式处理一个推荐问题从根本上改变了推荐引擎。到目前为止咱们所见到的全部推荐算法都是一个具备一个偏好返回值的函数。为 了给一篇文章推荐一个新的链接,咱们须要去遍历全部的文章-文章的链接;由于推荐过程须要全部的这些数据。然而,如此大量的数据,咱们要遍历所有或者大部 分不可能一次性完成。咱们以前所介绍的方法已经变得再也不适用了,至少对于目前的问题形式。接下来分布式推荐引擎将为你我点亮一展明灯。
须要指出的是,分布式处理一个问题不能提搞计算的效率,相反,它相对于单机处理要消耗更多的资源。好比,在不少机器以前传输 数据须要消耗网络带宽。这种计算每每要被结构化,包括中间结果的排序,它会占用一些时间去进行序列化、存储以及反序列化等过程。并且这些是很是占用内存和消耗电能的。
须要注意的是,这样的计算须要在线下执行,由于即便计算不多的数据也是秒级别的,而不是毫秒级别的。这样它就不能对用户的请求作出实时响应。通常地,这样的计算和存储会按期的进行,而后在运行时返回给用户。
然而,这种作法能够为推荐系统在处理大规模数据时提供一种途径,这是单机处理方案没法具有的。由于分布式计算能够从不少机器 上利用计算资源,把那些未使用、零散的计算资源整合在一块儿,从而在计算能力上超越专用计算机。最后,分布式计算能够使用更少的时间完成任务,虽然它须要更多对原料处理的过程和时间。通常而言,对于同一个问题,分布式要比单机的计算多消耗一倍的CPU资源。若是咱们用10CPU,那么速度将会是单机处理的5 倍,并且对于机器的利用率也大大提升了。
对于如此规模的数据,咱们但愿使用分布式处理的方法。首先,咱们会对基于项目的算法的分布式变异版本进行描述。它在某种程度上和之前非分布式的版本很类似。固然它看起来是彻底不一样的,由于之前的算法不曾被翻译到分布式的世界。接下来咱们要用Hadoop来跑一跑。
这个算法由一些简单的矩阵操做都成,它易于解释而且容易实现。若是你上次接触矩阵是好几年前了,不要担忧,最棘手的操做只有矩阵乘法(若是您连矩阵乘法都不知道,拜托,那还搞啥数据挖掘...)。这里保证没有什么行列式、行分解、特征值等等。
回忆一下,基于项目的推荐,咱们依赖于ItemSimilarity的实现。它能够提供两个项目间的类似程度。试想一下,咱们会把计算完的类似度存放在一个很大的方阵里面,行和列和项目一一对应。每一行(或者每一列)表明了一个特定的项目与其余项目的类似度的一个向量。事实上 它是个对称方阵。由于X与Y的类似度就是Y与X的类似度。
对与这个算法,咱们须要一个叫作“协同矩阵(co-occurrence matrix)”的东西。咱们用两个不一样项目同时 被喜欢的次数(协同因子)来代替以前类似度,这样能够构造出一个协同矩阵。好比,9个用户同时对X,Y感兴趣,那么他们的协同因子就是9,若是X,Y没有 同时被任何用户喜欢那么协同因子就是0,对于项目对本身的协同因子咱们不考虑,或者说咱们不去计算它。
协同因子很像类似度;两个项目同时出现能够描述这两个项目的类似程度。因此,正如咱们以前所看到的,协同矩阵扮演了ItemSimilarity所须要的数据的角色。
表 6.1 样本集中的协同矩阵。第一行和第一列分别是项目序号。
生成矩阵的过程就是简单的计数,这个矩阵和偏好值无关。一会咱们会对这些值进行计算。表6.1 表示了咱们通篇用到的一个小样例数据集所产生的协同矩阵。像上面所说,它是个对称方阵。有7个项目,矩阵有7行7列,对角线上的值将不会被使用,为了矩阵显示完整,咱们暂且把数据写 在上面。
下一步就是咱们把先前的推荐方法转化为一个基于矩阵的分布式模型,咱们须要把用户对项目的偏好看做是一个向量。这一步你已经作到了。当咱们使用欧几里德距离来度量用户类似度时,只需把用户当作是空间里的点,而类似度就是点之间的距离。
一样的,在模型中,用户的偏好就是一个n维的向量,每一个维度表明一个项目。偏好值就是向量的每一个份量。0表明用户对该项目无偏好。这个向量是稀疏的,不少份量都是0,由于实际中的用户仅对不多的项目有偏好。
例如,在上面的小样本数据集中,用户3的向量就是[2.0, 0.0, 0.0, 4.0, 4.5, 0.0, 5.0]。为了完成推荐,每一个用户都须要这样一个向量。
为了给用户3产生推荐结果,只须要用矩阵去乘以他的用户向量,如6.2表中所示。
花一些时间回忆一下矩阵乘法把,若是须要来这里看看:(http://en.wikipedia.org/wiki/Matrix_multiplication )。协同矩阵和用户向量的乘积是一个向量,维度个数等于项目的个数。这个向量就是咱们要的推荐结果。份量的值越大说明该项目的推荐排名越靠前。
表6.2 协同矩阵与用户3向量(U3)的乘积,最后用R来表示结果。
表6.2 展现了协同矩阵与U3的乘法运算过程,以及获得最终的推荐结果R。对于用斜体表示分数的项目10一、10四、 105还有107,咱们彻底忽略他们的结果,由于咱们事先知道用户3对这些项目产生了偏好。剩下的结果中,103的分数是最高的,用黑体表示,那么103 就应该排在推荐结果中的首位。其余按照分数往下排便可。
让咱们停下来理解一下上面产生的结果,为什么R中值较高的项目是较好的推荐呢?R中的没个份量是估计出来的偏好值,可是为什么这个值就能够来表征用户对该项目的偏好呢?
回顾一下上面的计算过程,好比,R的第三个份量来自于矩阵的第三行与用户向量的点积。拿上面的数据就是:
4(2.0) + 3(0.0) + 4(0.0) + 3(4.0) + 1(4.5) + 2(0.0) + 0(5.0) = 24.5
矩阵的第三行包含了项目103与其余项目的协同因子。直觉告诉咱们,若是103和该用户所偏好的其余项目比较类似,那么用户 极可能会对103也有偏好。这个公式就是项目的协同因子与用户偏好乘积之和。若是103和该用户所偏好的不少项目同时出现时,那么103的分数就会越高。 相应的项目偏好越大也会对分数有所贡献。这就是为什么R能够做为预测结果。
须要说明的是,R不能表明用户对该物品的偏好值,由于他们对于偏好值来讲太大了。咱们能够经过归一化来将这些值变位符合要求的偏好值。若是你愿意的话,能够本身对结果处理一下。可是对于咱们的目标来讲,归一化是不必的,由于咱们关心的只是这些项目的得分排序,而不是具体的 值。
这是个颇有意思的事情,可是用户大规模处理的算法到底是什么样子的呢?
算法的每一个单元在任什么时候候都仅仅包含了数据的一个子集。例如,在建立用户向量时,每一个计算单元都只为一个特定的用户去计算。 计算协同矩阵时,计算单元仅为一个项目去计算它的协同因子向量。产生推荐结果时,计算单元只是用矩阵的一个行或者一列去乘以用户向量。另外,一些计算单元能够立足于收集这些相关数据。好比,用户向量的建立,它所需的每一个偏好值能够各自单独去计算,而后收集。
MapReduce范式专门为此而生。
本章包括
1 实战操做了解聚类
2.了解类似性概念
3 使用mahout运行一个简单的聚类实例
4.用于聚类的各类不一样的距离测算方法
做为人类,咱们倾向于与志同道合的人合做—“鸟的羽毛汇集在一块儿。咱们可以发现重复的模式经过联系在咱们的记忆中的咱们看到的、听到的、问道的、尝到的东 西。 例如,相比较盐 ,糖可以是咱们更多地想起蜜。因此咱们把糖和蜜的味道结合起来叫他们甜蜜。甚至咱们不知道甜蜜的味道,可是知道他跟世界上全部的含糖的东西是类似的,是同一类的。咱们还知道它与盐是不一样类的东西。无心中,咱们不一样的味道使用了聚类。把糖和盐作了聚类,每一个组有数百个项目。
在天然界中,咱们观察不一样类型的群体。认为猿与猴是同一种灵长类动物。全部的猴子 都有一些性状如短高度,长尾巴,和一个扁平的鼻子。相反,猿类有较大的尺寸,长长的手臂,和更大的头。猿看起来不一样于猴子,但都喜欢香焦。因此咱们能够认为猿和猴子做为两个不一样的组,或做为一个单一的爱香蕉的灵长类动物群。咱们考虑一个集群彻底取决于咱们选择的项目之间的类似性测量的特色(在这种状况下, 灵长类动物)。
在这一章中,从mahout学习的聚类的例子中,咱们将会知道聚类是什么,如何有数据概念联系起来。让咱们从基础开始吧!
7.1 聚类的基础
聚类的过程是怎么样的呢?假如你能够去有成千上万的书籍的图书馆。在图书馆内 ,图书是杂乱无章的。要找到想读的书必须横扫全部的书籍,一本一本的才能特定的书。这不只是繁琐和缓慢,并且很是枯燥。
按照标题的字母顺序排序会对读者经过标题寻找有很大的帮助,若是大多数人只是简单地浏览一下,只是找一个大概的主题的书籍呢?这样经过按照书籍的主题进行分类要比按照标题的字母顺序更有用。可是如何进行分组呢?刚刚接手这份工做,你也不会知道全部的书籍是什么的?是冲浪的、浪漫的,或你没有遇到过的课 题。
经过按主题把书籍分类,你不得不把全部书放在同一线上,一本一本的开始阅读。当你遇到一本书的内容是相似之前的一本书,你就返回去把它们放在在一块儿。当你完成,你从数千上万的书中获取到你要的主题的一堆书。
干得好!这是你的第一个聚类的经验。若是一百个主题组太多了,你就得从头开始和重复刚才的过程得到书堆,直到你的主题,从另外一个堆是彻底不一样的。
聚类是全部关于组织项目从一个给定集合成一组相似的项目。在某些方面,这些集群能够被认为是做为项目类似集,可是与其余集群项目不一样的。
聚类集合包含三项
● 算法 ———–这是用来组书籍的方法
●类似性和差别性的概念——-一个在前面讨论的,依赖于这本书是否属于已经存在的堆,仍是应 该另组新一堆的判断。
●终止条件———图书馆的例子中,当达到这些书不能堆积起来了,或这些堆已经至关不一样的,这就是终止
在这个简单的例子中,圈出来的显然是基于距离三个集群,表明了聚类的结果。圆是一个在聚类方面是一个很好的方法。因为群组经过中心点和半径来定义的,圆的中心被叫为群重心,或者群平均(平均值),群重心的坐标是类簇中的全部点的x,y轴的平均值
项目的类似性测量
图7.1x-y平面图的点,圆圈表明了聚类,在平面团中的点归类了单个逻辑群组,聚类算法有益于识别群组
在本章中,咱们将聚类可视化为一个几何问题。聚类的核心是使用几何的技术表达不一样距离的测算。咱们找到一些重要的距离测算法和聚类关系。平面聚类点与文本聚类之间的具体类似性就能够抽象出来。
在后面的章节中,咱们探讨了普遍用于聚类的方法数据,以及mahout 中使用
方法。图书馆的例子是将书分堆直到达到必定阈值的一种策 略。在这个例子中造成的簇的数目取决于数据;基于许多书和临界值,你可能发现了100后者20,甚至是1个类簇。一个更好的策略是创建目标簇,而不是一个临界值,而后找到最好的群组与约束。接下来咱们将详细的介绍目标簇和不一样的变量
7.2项目的类似性测量
聚类的重要问题是找到一方法,经过任何两个数中的一个数来量化类似性。注意一下咱们整片文章中使用的专业术语 :项目和点,这两个是聚类数据的单位。
在X-Y平面的例子,类似性的度量(类似性度量)的分为两个点之间的欧几里德距离。图书馆的例子没有这种清晰的数学手段,而不是彻底依赖的智慧馆员之间的类似度来判断书。这工做不在咱们的案例,由于咱们须要一个度量,可在计算机上实现.
一个可能的度量是基于两本书的标题共同含有的词的数量。基于哈利·波特:哲学家的石头和哈利·波特这两本书:阿兹卡班的囚徒中常见的三个词:哈利、波特、the。即时魔戒也:两塔是相似于哈利·波特系列,这一措施类似不会捕获这一切。你须要改变的类似性度量来对书籍自己的内容账户。你能够将单词计数。
只惋惜,说的容易作起来难。这些书不只有几百个网页的文本,并且英语的特色也使的分类方法更加困难。在英语文本中有一些很频繁的次例如 a,an ,the 等等,它老是常常发生但又不能说明这是这两本书的类似点。
为了对抗这种影响,你能够在计算中使用的加权值,而且使用低权重表示这些词来减小对类似度值的影响。在出现不少次的词使用低权重值,出现少的用高权重。你能够衡量一个特定的书常常出现的,好比那些强烈建议内容的书籍–相似于魔术类的哈利波特。
你给书中的每个单词一个权重,就能算出这本中的类似性–就是全部词的词频乘以每个词的权重的和。若是这两本书的长度相同,那么这个就是一个比较适当的方法。
若是一本书有300页,另外一本有1000页呢?固然书页大的书的词也多。
K-means须要用户设定一个聚类个数(k)做为输入数据,有时k值可能很是大(10,000),这是Mahout闪光的(shines)地方,它确保聚类的可测量性。
为了用k-means达到高质量的聚类,须要估计一个k值。估计k值一种近似的方法是根据你须要的聚类个数。好比100万篇文章,若是平均500篇 分为一类,k值能够取2000(1000000/500)。这种估计聚类个数很是模糊,但k-means算法就是生成这种近似的聚类。
下面看一下k-means算法的细节,K-means算法是硬聚类算法,是典型的局域原型的目标函数聚类方法的表明,它是数据点到原型的某种距离做为优化的目标函数,利用函数求极值的方法获得迭代运算的调整规则。算法采用偏差平方和准则函数做为聚类准则函数。K-means算法是很典型的基于距离的聚类算法,采用距离做为类似性的评价指标,即认为两个对象的距离越近,其类似度就越大。该算法认为簇是由距离靠近的对象组成的,所以把获得紧凑且独立的簇做为最终目标。k个初始类聚类中心点的选取对聚类结果具备较大的。
算法步骤:
(1)随机选取任意k个对象做为初始聚类中心,初始表明一个簇;
(2)计算点到质心的距离,并把它归到最近的质心的类;
(3)从新计算已经获得的各个类的质心;
(4)迭代2~3步直至新的质心与原质心相等或小于指定阈值,算法结束。
这种两步算法是最大指望算法(EM)的典型例子,
第一步是计算指望(E),利用对隐藏变量的现有估计值,计算其最大似然估计值;
第二步是最大化(M),最大化在 E 步上求得的最大似然值来计算参数的值。
M 步上找到的参数估计值被用于下一个 E 步计算中,这个过程不断交替进行。
K-mean聚类用到KMeansClusterer或KMeansDriver类,前一个是在内存(in-memory)里对节点聚类,后者采用 MapReduce任务执行。这两种方法均可以就像一个普通的Java程序运行,而且能够从硬盘读取和写入数据。它们也能够在hadoop上执行聚类,通 过度布式文件系统读写数据。
下面举例,使用一个随机点生成器函数来建立一些点。这些点生成矢量格式的点做为一个正态分布围绕着一个中心。使用Mahout的in-memory K-means 聚类方法对这些点聚类。
建立节点:generateSamples方法,取(1,1)为中心点,标准差为2,400个围绕着(1,1)的随机点,近似于正态分布。另外又取了2个数据集,中心分别为(1,0)和(0,2),标准差分别为0.5和0.1。
KMeansClusterer.clusterPoints()方法用到一下参数:
Mahout-example里的DisplayKMeans类能够直观的看到该算法在二维平面的结果,9.2节将介绍运行一个Java Swing application的DisplayKMeans。
若是数据量很大时,应采起MapReduce运行方式,将聚类算法运行在多个机器上,每一个mapper获得一个子集的点,每一个子集运行一个mapper。这些mapper任务计算出最近的集群做为输入流。
K-means聚类的MapReduce Job
采用KMeansDriver类的run()方法,须要输入的参数有:
public static void run(Configuration conf,Path input,PathclustersIn,Path output,
DistanceMeasure measure,
double convergenceDelta,
int maxIterations,
boolean runClustering,
boolean runSequential)
采用SparseVectorsFromSequenceFile工具,将sequenceFile转换成Vector,由于K-means算法须要用户初始化k个质心。