基于Spark的音乐专辑数据处理与分析 spark歌曲
#音乐推荐和Audioscrobbler数据集
#1. 数据集
http:///~bergstrj/audioscrobbler_data.html 下载具体地址为:
http://www.iro.umontreal.ca/~lisa/datasets/profiledata_06-May-2005.tar.gz
#1.数据
user_artist_data.txt包含141000个用户和160万个艺术家,记录了约2420万条用户播放艺术家歌曲的信息,其中包含播放次数
数据集在artist_data.txt文件中给出了每位艺术家的ID和对应的名字。请注意,记录播放信息时,客户端应用提交的是艺术家的名字。
为了将拼写错误的艺术家ID或ID变体对应到该艺术家的规范ID,数据集提供了artist_alias.txt文件。
#2. 交替最小二乘(ALS)推荐算法
根据这个隐式反馈数据选择一个合适的推荐算法。这个数据集只记录了用户和歌曲之间的交互情况。
我们要找的算法是不需要用户和艺术家的属性信息,这类算法通常称为协同过滤算法。
举个例子,根据两个用户的年龄相同来判断他们可能有相似的爱好,这不叫协同过滤。相反,根据两个用户播放过很多相同的歌曲来判断他们可能都喜欢
某首歌,这才叫协同过滤。
本实例将用到潜在因素模型中的一种模型。潜在因素模型试图通过数量相对少的未被观察到的底层原因,来解释大量用户和产品之间可观察到的交互。
说的更明确一点,本实例使用的是一种矩阵分解模型。
数学上,这些算法将用户和产品数据当成一个大矩阵A,矩阵第i行和第j列上的元素都有值,代表用户i播放过艺术家j的音乐。矩阵A是稀疏的:A中大多数
元素都是0,因为相对于所有可能的用户-艺术家组合,只有很少一部分组合会出现在数据中。
算法将A分解为两个小矩阵X和Y的乘积。矩阵X和矩阵Y非常"瘦",因为A有很多行和列,但X和Y的行很多而列很少(列数用k表示)。这k个列就是潜在因素,用于
解释数据中的交互关系。
由于k的值很小,矩阵分解算法只能是某种近似。
将ALS算法用于隐性数据矩阵分解时,ALS矩阵分解要稍微复杂一点儿。它不是直接分解输入矩阵A,而是分解由0和1组成的矩阵P,当A中元素为正时,P中对应
元素为1,否则为0。A中的具体值后面会以权重的形式反映出来。
#3.准备数据
构建模型的第一步是了解数据,对数据进行解析或转换,以便在Spark中做分析。
Spark MLlib的ALS算法要求用户和产品的ID必须是数值型,并且是32位非负整数。这意味着大于Integer.MAX_VALUE(2147483647)的ID都是非法的。
默认情况下,RDD为每个HDFS块生成一个分区,将HDFS块大小设为典型的128MB。由于HDFS文件大小为400多M,所有文件被拆分为4个分区。但是针对ALS这类需要
消耗更多的计算资源,建议减少数据块大小以增加分区个数会更好。减少数据块大小能使Spark处理任务时同时使用的处理器核数更多。
val rawUserArtistData = sc.textFile("/user/ds/user_artist_data.txt",8) #可以设置为集群处理器总核数
文件的每行包含一个用户ID,一个艺术家ID和播放次数,用空格分隔。
可以看出最大的用户ID和艺术家ID分别为2443548和10794401,都远小于2147483647,因此没有必要做进一步处理。
本例中的艺术家名字对应模糊的数值ID,这些信息包含在artist_data.txt中。
现在artist_data.txt包含艺术家ID和名字,它们用制表符分隔。但是直接解析会出错,因为有的格式不对。
这里使用span()用第一个制表符将一行拆分成两部分,接着将第一部分解析为艺术家ID,剩下的部分作为艺术家的名字(去掉了空白的制表符)。
因为map函数要求对每个输入必须严格返回一个值,因此这里不合适。
使用flatMap可以解决,flatMap中的函数本可以简单返回一个空List,或一个只有一个元素的List,但使用Some和None更合理。
下面是好的解决方法:
artist_alias.txt将拼写错的艺术家ID和非标准的艺术家ID映射为艺术家的正规名字。其中每行有两个ID,用制表符分隔。
有必要将"不良的"艺术家ID映射到"良好的"ID。
注意:数据的某些行没有艺术家的第一个ID,所以需要过滤掉。
我们看到第一条将ID为6803336映射为1000010。我们可以从RDD进行查找:
可以看出,这条记录将" Aerosmith (unplugged)"映射为"Aerosmith"。
#4 构建第一个模型
经过上面的处理,虽然符合Spark MLlib的ALS算法实现的要求,但我们还需要额外做两个转换。
第一,如果艺术家ID存在一个不同的正规ID,我们要用别名数据集将所有的艺术家ID转换为正规ID。
第二,需要把数据集转换成Rating对象,Rating对象是ALS算法实现对"用户-产品-值"的抽象。
#如果艺术家存在别名,取得艺术家的别名,否则取得原始名字
虽然刚创建的artistAlias是驱动程序本地的一个Map,可以在RDD的map()函数中直接使用它。这是没有问题的,因为artistAlias会随着任务一起被
自动复制。但是它可不小,要消耗15MB内存,就是序列化也得占用几M字节。毕竟每个JVM中有很多任务,所以发送和存储太多副本非常浪费资源。
针对上面的这种情况,我们可以为artistAlias创建一个广播变量。使用广播变量时,Spark对集群中每个executor只发送一个副本,并且在内存里也只保存一个副本。
如果有几千个任务都在executor上并行执行,使用广播变量能节省巨大的网络流量和内存。
#广播变量
Spark执行一个阶段时(Stage),会为待执行函数建立闭包,也就是该阶段所有任务所需信息的二进制形式。这个闭包包括驱动程序里函数引用的所有数据结构。
Spark把这个闭包发送到集群的每个executor上。
当许多任务需要访问同一个数据结构时,我们应该使用广播变量。
好处:
第一,在每个executor上将数据缓存为原始的Java对象,不用为每个任务执行反序列化
第二,在多个作业和阶段之间缓存数据
#最后,我们构建模型
scala> val model = ALS.trainImplicit(trainData,10,5,0.01,1.0)
这样就构建了一个MatrixFactorizationModel模型。这个操作可能要花费几分钟或者更长时间,具体时间取决于所用的集群。
对于每个用户和产品,模型都包含一个有10个值的特征向量。本例中总共超过170万个特征向量。模型用两个不同的RDD,他们分别
表示"用户-特征"和"产品-特征"这两个大型矩阵。
特征向量是一个包含10个数值的数组。
如果想查看某些特征向量,可以使用如下代码,mkString把向量翻译为可读的形式,在Scala中mkString方法常用于把集合元素表示以某种形式分隔的字符串:
trainImplicit()中包含的其他参数都是超参数,他们的值将影响模型的推荐质量。
#逐个检查推荐结果
比如我们看一下 2093760 的例子。
找到用户2093760的行:
收集不同的艺术家:
我们可以将rawArtistsForUser的RDD的关系给列出来:
过滤艺术家,取出艺术家并打印:
用户播放过的艺术家既有大众流行音乐的也有嘻哈风格的。
结果由Rating对象组成,包括用户ID(重复的),艺术家ID和一个数值。虽然字段名称叫rating,但其实不是估计的得分。
对这类的ALS算法,它是一个在0到1之间的模糊值,值越大,推荐质量越好。它不是概率,但可以把它理解成对0/1值的一个估计,0表示用户不喜欢播放艺术家的歌曲,1表示
喜欢播放艺术家的歌曲。
得到所推荐的艺术家的ID之后,就可以用类似的方法查到艺术家的名字:
结果可能不怎么样。
下一课我们将介绍如何提高评价推荐质量。
摘自《Spark高级数据分析》
网址:基于Spark的音乐专辑数据处理与分析 spark歌曲 http://www.mxgxt.com/news/view/1170702
相关内容
Ion Stoica与分布式计算的双星:Spark与Ray的成功之道七成员经历重重考验 TEAM SPARK火星团正式出道
利用动态资源分配优化Spark应用资源利用率
Ion Stoica:做成Spark和Ray两个明星项目的秘笈从中我们可以通过第一手资料了解到发起Spark和Ray、成
基于大数据的舆情分析系统架构
有哪些好用的大数据分析平台推荐?
基于大数据的社交网络分析与应用研究.docx
大数据的舆情分析
基于Hadoop的明星社交媒体影响力数据挖掘平台:设计与实现
推热转,Karina和Giselle直播跳《Dopamine》、《Up》、《Bored》、《Spark》