Movie recommendations and more with Spark - Crouching Data, Hidden Markov
文章的灵感来自 Edwin Chen关于Scalding的帖子。我鼓励你先阅读那篇文章!Spark代码改编自他的Scalding代码,可在 此处获得。
正如Ed的帖子所述,Scalding是一个用于Hadoop MapReduce的Scala DSL,它使编写MapReduce工作流程变得更容易,更自然,更简洁。Scala代码最终通过 Cascading编译为MapReduce作业。
Scalding
Scalding 项目是群集计算框架,强调低延迟作业执行和内存中缓存,以提供速度。因此,它可以比Hadoop MapReduce(当所有数据都缓存在内存中)快100倍。它是用Scala编写的,但也有Java和Python API。它与HDFS和任何Hadoop完全兼容 InputFormat/OutputFormat
,但独立于Hadoop MapReduce。
Spark API与Scalding有许多相似之处,提供了一种编写自然Scala代码的方法,而不是 Mappers
和 Reducers
。以Ed为例:
1 2 | |
1 2 | |
电影相似度
我最近一直在用Spark进行很多实验,并认为将Ed的计算方法与Scalding和Spark中的电影相似性进行比较会很有意思。所以我把他的Scalding代码移植到了Spark上,我们将比较这两个代码。有关Spark API的基本介绍,请参阅 Spark Quickstart。
首先,我们从文件中读取评级。由于我无法访问不错的Twitter推文数据源,因此我使用了 MovieLens 100k评级数据集。训练集评级在一个名为的文件中 ua.base
,而电影项目数据在 u.item
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | |
与Scalding的 Tsv
方法(从HDFS读取TSV文件)类似,Spark的 sc.textFile
方法从HDFS读取文本文件。但是,由我们来指定如何拆分字段。
此外,Spark的连接API比Scalding的更低级别,因此我们必须 groupBy
先进行转换,然后 join
进行 flatMap
操作以获取我们想要的字段。烫伤实际上做了类似的事情 joinWithSmaller
。
计算相似度
为了确定两部电影彼此之间的相似程度,我们必须(按照Ed的帖子):
- 对于每对电影A和B,找到所有同时评价A和B的人。
- 使用这些评级来形成电影A矢量和电影B矢量。
- 计算这两个向量之间的相关性。
- 每当有人观看电影时,您都可以推荐与其最相关的电影。
这是基于项目的协作过滤。那么让我们计算上面的前两个步骤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
1 2 3 4 5 6 7 8 9 | |
请注意API与功能操作的相似之处 filter
- 它们各自只需要一个Scala闭包。然后,我们计算每个评级向量的各种向量度量(大小,点积,范数等)。我们将使用这些来计算电影对之间的各种相似度量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
相似度量
对于每个电影对,我们计算 相关性, 正则化相关性, 余弦相似度和 Jaccard相似度(参见Ed的帖子和完整细节的代码)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
这里的好处是,一旦原料输入度量自己计算,我们就可以使用完全相同的功能,从例子来计算的相似性指标如从上面可以看出-我简单地复制和粘贴埃德的 correlation
, regularizedCorrelation
, cosineSimilarity
和 jaccardSimilarity
功能!
一些结果
那么,将所有这些结合在一起后,结果会是什么样的?由于我使用了不同的输入数据源,我们不会得到相同的结果,但我们希望它们中的大多数都有意义。与Ed的结果类似,我发现使用raw会 correlation
导致次优相似性(至少从眼球和“感觉检查”),因为一些电影对很少有共同的评价者(许多只有一个共同的评价者)。
我也发现 cosine similarity
在“感觉检查”的基础上做得不好,这有点令人惊讶,因为这通常是协同过滤的标准相似性度量。这似乎是由于很多电影的余弦相似度为1.0,所以也许我搞砸了某个地方的计算(如果你发现错误请告诉我)。
无论如何,这里是与Die Hard(1998)最相似的前10部电影,排名依据 regularized correlation
:
电影1 | 电影2 | 关联 | Reg Correlation | 余弦相似度 | Jaccard相似度 |
---|---|---|---|---|---|
死硬(1988) | 死硬:复仇(1995) | 0.5413 | 0.4946 | 0.9692 | 0.4015 |
死硬(1988) | 死硬2(1990) | 0.4868 | 0.4469 | 0.9687 | 0.4088 |
死硬(1988) | 香蕉(1971) | 0.5516 | 0.4390 | 0.9745 | 0.1618 |
死硬(1988) | 好,坏和丑,(1966) | 0.4608 | 0.4032 | 0.9743 | 0.2518 |
死硬(1988) | 寻找红十月,(1990) | 0.4260 | 0.3944 | 0.9721 | 0.4098 |
死硬(1988) | 城市切片机II:卷曲金的传说(1994) | 0.5349 | 0.3903 | 0.9506 | 0.1116 |
死硬(1988) | 油脂2(1982) | 0.6502 | 0.3901 | 0.9449 | 0.0647 |
死硬(1988) | 星际迷航:可汗之怒(1982) | 0.4160 | 0.3881 | 0.9675 | 0.4441 |
死硬(1988) | 球体(1998) | 0.7722 | 0.3861 | 0.9893 | 0.0403 |
死硬(1988) | 梦之场(1989) | 0.4126 | 0.3774 | 0.9630 | 0.3375 |
看起来很合理!以下是与Il Postino最相似的10个:
电影1 | 电影2 | 关联 | Reg Correlation | 余弦相似度 | Jaccard相似度 |
---|---|---|---|---|---|
Postino,Il(1994) | 瓶火箭(1996) | 0.8789 | 0.4967 | 0.9855 | 0.0699 |
Postino,Il(1994) | 寻找理查德(1996) | 0.7112 | 0.4818 | 0.9820 | 0.1123 |
Postino,Il(1994) | Ridicule(1996) | 0.6550 | 0.4780 | 0.9759 | 0.1561 |
Postino,Il(1994) | 当我们是国王(1996) | 0.7581 | 0.4773 | 0.9888 | 0.0929 |
Postino,Il(1994) | 母亲之夜(1996) | 0.8802 | 0.4611 | 0.9848 | 0.0643 |
Postino,Il(1994) | Kiss Me,Guido(1997) | 0.9759 | 0.4337 | 0.9974 | 0.0452 |
Postino,Il(1994) | 脸上的蓝色(1995) | 0.6372 | 0.4317 | 0.9585 | 0.1148 |
Postino,Il(1994) | 奥赛罗(1995) | 0.5875 | 0.4287 | 0.9774 | 0.1330 |
Postino,Il(1994) | 英国病人,(1996) | 0.4586 | 0.4210 | 0.9603 | 0.2494 |
Postino,Il(1994) | Mediterraneo(1991) | 0.6200 | 0.4200 | 0.9879 | 0.1235 |
星球大战怎么样?
电影1 | 电影2 | 关联 | Reg Correlation | 余弦相似度 | Jaccard相似度 |
---|---|---|---|---|---|
星球大战(1977) | 帝国反击战,(1980年) | 0.7419 | 0.7168 | 0.9888 | 0.5306 |
星球大战(1977) | 绝地归来(1983年) | 0.6714 | 0.6539 | 0.9851 | 0.6708 |
星球大战(1977) | 迷失方舟的攻略(1981) | 0.5074 | 0.4917 | 0.9816 | 0.5607 |
星球大战(1977) | 认识John Doe(1941) | 0.6396 | 0.4397 | 0.9840 | 0.0442 |
星球大战(1977) | 爱在下午(1957) | 0.9234 | 0.4374 | 0.9912 | 0.0181 |
星球大战(1977) | 年度人物(1995年) | 1.0000 | 0.4118 | 0.9995 | 0.0141 |
星球大战(1977) | 当我们是国王(1996) | 0.5278 | 0.4021 | 0.9737 | 0.0637 |
星球大战(1977) | 哭泣,心爱的国家(1995) | 0.7001 | 0.3957 | 0.9763 | 0.0257 |
星球大战(1977) | 成为或不成为(1942) | 0.6999 | 0.3956 | 0.9847 | 0.0261 |
星球大战(1977) | 爱德华·D·伍德的幽灵世界,(1995) | 0.6891 | 0.3895 | 0.9758 | 0.0262 |
最后, 与星球大战最 不相似的10个怎么样?
电影1 | 电影2 | 关联 | Reg Correlation | 余弦相似度 | Jaccard相似度 |
---|---|---|---|---|---|
星球大战(1977) | 父亲节(1997年) | -0.6625 | -0.4417 | 0.9074 | 0.0397 |
星球大战(1977) | 杰森的抒情诗(1994) | -0.9661 | -0.3978 | 0.8110 | 0.0141 |
星球大战(1977) | 闪电杰克(1994) | -0.7906 | -0.3953 | 0.9361 | 0.0202 |
星球大战(1977) | 标记为死亡(1990) | -0.5922 | -0.3807 | 0.8729 | 0.0361 |
星球大战(1977) | 混合坚果(1994) | -0.6219 | -0.3731 | 0.8806 | 0.0303 |
星球大战(1977) | Poison Ivy II(1995) | -0.7443 | -0.3722 | 0.7169 | 0.0201 |
星球大战(1977) | 在感官境界(Ai no corrida)(1976) | -0.8090 | -0.3596 | 0.8108 | 0.0162 |
星球大战(1977) | 发生了什么......(1994) | -0.9045 | -0.3392 | 0.8781 | 0.0121 |
星球大战(1977) | 女性变态(1996) | -0.8039 | -0.3310 | 0.8670 | 0.0141 |
星球大战(1977) | Celtic Pride(1996) | -0.6062 | -0.3175 | 0.8998 | 0.0220 |
我会留给你决定准确性。
结论和后续步骤
希望这能够体现Spark以及它如何以与Scalding和MapReduce非常相似的方式使用 - 具有HDFS兼容性,内存缓存功能,低延迟执行和其他分布式内存原语(如广播变量和累加器); 更不用说通过Scala / Spark控制台以及Java和Python API进行交互式分析了! 在这里查看文档,教程和示例。
从上面的代码片段中可以明显看出,Scalding的API在进行复杂的字段操作和连接时更加清晰,因为能够将命名字段设置为Scala Symbols
,例如 tweets.map('tweet -> 'length) { tweet : String => tweet.size }
Spark的API中缺少命名字段会导致一些混乱的元组解包并使跟踪哪些字段更复杂。这可能是Spark的一个有趣的潜在补充。