您的位置:首页 > 其它

Mahout in action 中文版-6.分布式推荐计算

2014-01-02 10:09 453 查看
6 分布式推荐计算

本章概述:

分析维基百科上的一个大数据集

利用Hadoop和分布式计算产生推荐结果

伪分布式上存在的非分布式推荐

本书着眼于持续增长的数据集,从10条到100,000再到1千万再到1.7千万。不过这依然是中等大小的推荐系统所处理的数据。本章依然放手一搏,处理了来自维基百科语料库中的1.3亿条数据,这些数据主要是以文章对文章的连接形式存在的。在这些数据集中,文章既充当了用户,也充当了项目。这也显示了Mahout在特定情形下十分灵活的应用。

为满足演示目的,1.3亿的数据还是可管理的。但是对于单机处理推荐过程还是有一些困难的。这就需要使用一种新的推荐算法,通过Mahout基于的Mapreduce范式与Hadoop来实现分布式计算。

我们首先要检测一下维基百科的数据来认识一下它对于分布式推荐计算意味着什么。你将会学习到如何在分布式的环境下设计一个推荐器,因为这与非分布式的推荐计算有很大的不同。你也将看到Mahout如何把之前的算法设计翻译成基于MapReduce和Hadoop的实现。最后,你将运行一个完整的基于Hadoop的推荐Job程序。


6.1 分析维基百科数据集

我们从分析维基的数据开始,但是很快我们会发现由于问题规模而引起的问题。我们将很快退后几步去深入了解下分布式计算是如何执行的。

维基是一个由用户编写和维护的在线百科全书。据报道,在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感兴趣或者会偶然关联上的一些文章。


6.1.2 数据规模的考虑

在处理这样大的数据时,一个非分布式的推荐引擎可能就搞不定了。单单这些数据就要消耗JVM堆空间2GB大小,再加上Mahout程序所需空间,可能需要2.5GB。这已经超过了某些32位的机器的堆空间大小。也就是说,你需要一台64位的机器,今儿不换明儿也得换。再由于推荐算法固有的时间复杂度,推荐系统需要超过一秒的时间去完成推荐任务,这对于现代Web实时应用来说已经是非常慢了。

如果我们有足够多的硬盘,那么我们可以搭建这样一个平台。但是总有一天,随着数据的日益增多,到了十亿或者更多,所需的堆空间也达到了上限32GB呢?对了,也许有人会开始琢磨如何对数据降噪去减少数据的量,提高数据的精度。但是这并不能从根本上回避数据增长所带来的问题。

如果你的系统在处理数据规模上有限制的话,那么只能说你Out了。计算资源可以无限的增加;那么我们要解决的问题是如果把这些计算资源整合在一起去协同的完成任务。你的收益和制作一个超级计算机(计算能力的提升)所需的成本是不成比例的,所以我们应该想办法利用多个普通机器的计算资源。对于那些单点无任何联系的机器,堆在一起只能是浪费电源,最有效利用他们的方式就是联合它们去为推荐系统效力。

这些维基数据的大小代表了一个基于Mahout的实时推荐系统所处理数据的上限。——这其实已经超过现代的标准了。对于这样的数据规模,我们需要一个新的方法。


6.1.2 分布式计算的优缺点评估

根据上面说明的原因,我们不得以才使用多个普通机器与代替一个高性能机器。一个公司或学术组织可能拥有很多未充分利用的普通机器,这样这些机器额外的空闲资源就可以用来做推荐任务。另外有一些计算资源也可以通过云计算的提供商哪里得到,比如亚马逊EC2服务(http://aws.amazon.com)。



图 6.1 分布式可以将一个数据规模很大的问题化简成很多小规模数据的问题,从而分配给较小的服务器上去计算。

分布式处理一个推荐问题从根本上改变了推荐引擎。到目前为止我们所见到的所有推荐算法都是一个具有一个偏好返回值的函数。为了给一篇文章推荐一个新的连接,我们需要去遍历所有的文章-文章的连接;因为推荐过程需要所有的这些数据。然而,如此大量的数据,我们要遍历全部或者大部分不可能一次性完成。我们之前所介绍的方法已经变得不再适用了,至少对于目前的问题形式。接下来分布式推荐引擎将为你我点亮一展明灯。

需要指出的是,分布式处理一个问题不能提搞计算的效率,相反,它相对于单机处理要消耗更多的资源。比如,在很多机器之前传输数据需要消耗网络带宽。这种计算往往要被结构化,包括中间结果的排序,它会占用一些时间去进行序列化、存储以及反序列化等过程。而且这些是非常占用内存和消耗电能的。

需要注意的是,这样的计算需要在线下执行,因为即使计算很少的数据也是秒级别的,而不是毫秒级别的。这样它就不能对用户的请求做出实时响应。一般地,这样的计算和存储会定期的进行,然后在运行时返回给用户。

然而,这种做法可以为推荐系统在处理大规模数据时提供一种途径,这是单机处理方案无法具备的。因为分布式计算可以从很多机器上利用计算资源,把那些未使用、零散的计算资源整合在一起,从而在计算能力上超越专用计算机。最后,分布式计算可以使用更少的时间完成任务,虽然它需要更多对原料处理的过程和时间。一般而言,对于同一个问题,分布式要比单机的计算多消耗一倍的CPU资源。如果我们用10CPU,那么速度将会是单机处理的5倍,而且对于机器的利用率也大大提高了。


6.2 分布式处理一个基于项目的推荐算法

对于如此规模的数据,我们希望使用分布式处理的方法。首先,我们会对基于项目的算法的分布式变异版本进行描述。它在某种程度上和以前非分布式的版本很相似。当然它看起来是完全不同的,因为以前的算法未曾被翻译到分布式的世界。接下来我们要用Hadoop来跑一跑。


6.2.1 构造一个协同矩阵

这个算法由一些简单的矩阵操作都成,它易于解释并且容易实现。如果你上次接触矩阵是好几年前了,不要担心,最棘手的操作只有矩阵乘法(如果您连矩阵乘法都不知道,拜托,那还搞啥数据挖掘...)。这里保证没有什么行列式、行分解、特征值等等。

回忆一下,基于项目的推荐,我们依赖于ItemSimilarity的实现。它可以提供两个项目间的相似程度。试想一下,我们会把计算完的相似度存放在一个很大的方阵里面,行和列和项目一一对应。每一行(或者每一列)代表了一个特定的项目与其他项目的相似度的一个向量。事实上它是个对称方阵。因为X与Y的相似度就是Y与X的相似度。

对与这个算法,我们需要一个叫做“协同矩阵(co-occurrence matrix)”的东西。我们用两个不同项目同时被喜欢的次数(协同因子)来代替之前相似度,这样可以构造出一个协同矩阵。比如,9个用户同时对X,Y感兴趣,那么他们的协同因子就是9,如果X,Y没有同时被任何用户喜欢那么协同因子就是0,对于项目对自己的协同因子我们不考虑,或者说我们不去计算它。

协同因子很像相似度;两个项目同时出现可以描述这两个项目的相似程度。所以,正如我们之前所看到的,协同矩阵扮演了ItemSimilarity所需要的数据的角色。



表 6.1 样本集中的协同矩阵。第一行和第一列分别是项目序号。

生成矩阵的过程就是简单的计数,这个矩阵和偏好值无关。一会我们会对这些值进行计算。表6.1 表示了我们通篇用到的一个小样例数据集所产生的协同矩阵。像上面所说,它是个对称方阵。有7个项目,矩阵有7行7列,对角线上的值将不会被使用,为了矩阵显示完整,我们暂且把数据写在上面。


6.2.2 计算用户向量

下一步就是我们把先前的推荐方法转化为一个基于矩阵的分布式模型,我们需要把用户对项目的偏好看作是一个向量。这一步你已经做到了。当我们使用欧几里德距离来度量用户相似度时,只需把用户看成是空间里的点,而相似度就是点之间的距离。

同样的,在模型中,用户的偏好就是一个n维的向量,每个维度代表一个项目。偏好值就是向量的每个分量。0代表用户对该项目无偏好。这个向量是稀疏的,很多分量都是0,因为实际中的用户仅对很少的项目有偏好。

例如,在上面的小样本数据集中,用户3的向量就是[2.0, 0.0, 0.0, 4.0, 4.5, 0.0, 5.0]。为了完成推荐,每个用户都需要这样一个向量。


6.2.3 产生推荐结果

为了给用户3产生推荐结果,只需要用矩阵去乘以他的用户向量,如6.2表中所示。

花一些时间回忆一下矩阵乘法把,如果需要来这里看看:(http://en.wikipedia.org/wiki/Matrix_multiplication )。协同矩阵和用户向量的乘积是一个向量,维度个数等于项目的个数。这个向量就是我们要的推荐结果。分量的值越大说明该项目的推荐排名越靠前。

表6.2 协同矩阵与用户3向量(U3)的乘积,最后用R来表示结果。



表6.2 展示了协同矩阵与U3的乘法运算过程,以及得到最终的推荐结果R。对于用斜体表示分数的项目101、104、105还有107,我们完全忽略他们的结果,因为我们事先知道用户3对这些项目产生了偏好。剩下的结果中,103的分数是最高的,用黑体表示,那么103就应该排在推荐结果中的首位。其他按照分数往下排即可。


6.2.4 分析结果

让我们停下来理解一下上面产生的结果,为何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不能代表用户对该物品的偏好值,因为他们对于偏好值来说太大了。我们可以通过归一化来将这些值变位符合要求的偏好值。如果你愿意的话,可以自己对结果处理一下。但是对于我们的目标来说,归一化是没必要的,因为我们关心的只是这些项目的得分排序,而不是具体的值。


6.2.5 向分布式计算迈进

这是个很有意思的事情,但是用户大规模处理的算法究竟是什么样子的呢?

算法的每个单元在任何时候都仅仅包含了数据的一个子集。例如,在创建用户向量时,每个计算单元都只为一个特定的用户去计算。计算协同矩阵时,计算单元仅为一个项目去计算它的协同因子向量。产生推荐结果时,计算单元只是用矩阵的一个行或者一列去乘以用户向量。另外,一些计算单元可以立足于收集这些相关数据。比如,用户向量的创建,它所需的每个偏好值可以各自单独去计算,然后收集。

MapReduce范式专门为此而生。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: