# Spark数据分析之第4课

856人阅读 评论(0)

#音乐推荐和Audioscrobbler数据集
#1. 数据集
http://www-etud.iro.umontreal.ca/~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万条用户播放艺术家歌曲的信息，其中包含播放次数

#2. 交替最小二乘(ALS)推荐算法

#3.准备数据
hdfs dfs -ls /user/ds
-rw-r--r--   1 hdfs supergroup    2932731 2016-05-25 11:49 /user/ds/artist_alias.txt
-rw-r--r--   1 hdfs supergroup   55963575 2016-05-25 11:49 /user/ds/artist_data.txt
-rw-r--r--   1 hdfs supergroup  426761761 2016-05-25 11:50 /user/ds/user_artist_data.txt

Spark MLlib的ALS算法要求用户和产品的ID必须是数值型，并且是32位非负整数。这意味着大于Integer.MAX_VALUE(2147483647)的ID都是非法的。

scala> val rawUserArtistData = sc.textFile("/user/ds/user_artist_data.txt")

val rawUserArtistData = sc.textFile("/user/ds/user_artist_data.txt",8)  #可以设置为集群处理器总核数

#下面计算用户和艺术家的统计信息
scala> rawUserArtistData.map(_.split(' ')(0).toDouble).stats()
res6: org.apache.spark.util.StatCounter = (count: 24296858, mean: 1947573.265353, stdev: 496000.544975, max: 2443548.000000, min: 90.000000)

scala> rawUserArtistData.map(_.split(' ')(1).toDouble).stats()
res7: org.apache.spark.util.StatCounter = (count: 24296858, mean: 1718704.093757, stdev: 2539389.040171, max: 10794401.000000, min: 1.000000)

scala> val rawArtistData = sc.textFile("/user/ds/artist_data.txt")
rawArtistData: org.apache.spark.rdd.RDD[String] = /user/ds/artist_data.txt MapPartitionsRDD[16] at textFile at <console>:28

val artistByID = rawArtistData.map{line =>
val (id,name) = line.span(_ != '\t')
(id.toInt, name.trim)
}
artistByID: org.apache.spark.rdd.RDD[(Int, String)] = MapPartitionsRDD[17] at map at <console>:30

val artistByID = rawArtistData.flatMap{line =>
val (id,name) = line.span(_ != '\t')
if (name.isEmpty) {
None
} else {
try {
Some((id.toInt, name.trim))
} catch {
case e: NumberFormatException => None
}
}
}

artist_alias.txt将拼写错的艺术家ID和非标准的艺术家ID映射为艺术家的正规名字。其中每行有两个ID，用制表符分隔。

val rawArtistAlias = sc.textFile("/user/ds/artist_alias.txt")
val artistAlias = rawArtistAlias.flatMap { line =>
val tokens = line.split("\t")
if (tokens(0).isEmpty) {
None
} else {
Some(tokens(0).toInt, tokens(1).toInt)
}
}.collectAsMap() #collectAsMap 对(K,V)型的RDD数据返回一个单机HashMap。对于重复K的RDD元素，后面的元素覆盖前面的元素。
artistAlias: scala.collection.Map[Int,Int] = Map(6803336 -> 1000010, 6663187 -> 1992, 2124273 -> 2814, 10412283 -> 1...

res15: String = Aerosmith (unplugged)

res16: String = Aerosmith

#4 构建第一个模型

import org.apache.spark.mllib.recommendation._
val  trainData = rawUserArtistData.map { line =>
val Array(userID,artistID,count) = line.split(' ').map(_.toInt)
val finalArtistID = bArtistAlias.value.getOrElse(artistID,artistID)
Rating(userID,finalArtistID,count)
}.cache

#如果艺术家存在别名，取得艺术家的别名，否则取得原始名字

#广播变量
Spark执行一个阶段时(Stage)，会为待执行函数建立闭包，也就是该阶段所有任务所需信息的二进制形式。这个闭包包括驱动程序里函数引用的所有数据结构。
Spark把这个闭包发送到集群的每个executor上。

#最后，我们构建模型
scala> val model = ALS.trainImplicit(trainData,10,5,0.01,1.0)

scala> model.userFeatures.mapValues(_.mkString(", ")).first()
res11: (Int, String) = (90,-0.07274463027715683, 0.46505239605903625, 0.4246442914009094, 0.017407121136784554, -0.26859962940216064, -1.047317624092102, -0.656421959400177, -0.059907883405685425, -0.046106256544589996, -0.04561980441212654)

trainImplicit()中包含的其他参数都是超参数，他们的值将影响模型的推荐质量。

#逐个检查推荐结果

scala> val rawArtistsForUser = rawUserArtistData.map(_.split(' ')).filter {case Array(user,_,_) => user.toInt == 2093760}
rawArtistsForUser: org.apache.spark.rdd.RDD[Array[String]] = MapPartitionsRDD[146] at filter at <console>:26

scala> val existingProducts = rawArtistsForUser.map{ case Array(_,artist,_) => artist.toInt }.collect().toSet
existingProducts: scala.collection.immutable.Set[Int] = Set(1255340, 942, 1180, 813, 378)

scala> rawArtistsForUser.toDebugString
res19: String =
(4) MapPartitionsRDD[143] at filter at <console>:26 []
|  MapPartitionsRDD[142] at map at <console>:26 []
|  /user/ds/user_artist_data.txt MapPartitionsRDD[1] at textFile at <console>:21 []
|  /user/ds/user_artist_data.txt HadoopRDD[0] at textFile at <console>:21 []

scala> artistByID.filter { case (id,name) => existingProducts.contains(id)}.values.collect().foreach(println)
David Gray
Blackalicious
Jurassic 5
The Saw Doctors
Xzibit

#下面我们对5个用户做出推荐:
scala> val recommendations = model.recommendProducts(2093760,5)
recommendations: Array[org.apache.spark.mllib.recommendation.Rating] = Array(Rating(2093760,2814,0.0324184709372749), Rating(2093760,1001819,0.03097342837980681), Rating(2093760,1300642,0.030952322282742546), Rating(2093760,1007614,0.03035531332876626), Rating(2093760,4605,0.030150220216114847))

scala> recommendations.foreach(println)
Rating(2093760,2814,0.0324184709372749)
Rating(2093760,1001819,0.03097342837980681)
Rating(2093760,1300642,0.030952322282742546)
Rating(2093760,1007614,0.03035531332876626)
Rating(2093760,4605,0.030150220216114847

scala> val recommendedProductIDs = recommendations.map(_.product).toSet
recommendedProductIDs: scala.collection.immutable.Set[Int] = Set(2814, 1001819, 1300642, 4605, 1007614)

scala> artistByID.filter{ case(id,name) => recommendedProductIDs.contains(id) }.values.collect().foreach(println)
50 Cent
Snoop Dogg
Jay-Z
2Pac
The Game

0
0

* 以上用户言论只代表其个人观点，不代表CSDN网站的观点或立场
个人资料
• 访问：450531次
• 积分：7048
• 等级：
• 排名：第3220名
• 原创：248篇
• 转载：44篇
• 译文：2篇
• 评论：97条
我的新书

《基于Apache Kylin构建大数据分析平台》已出版，欢迎感兴趣的朋友购买！

查看详情

网上购买地址：
博客专栏
 Apache Kylin实战 文章：11篇 阅读：31173
 Greenplum/DeepGreen实战 文章：16篇 阅读：56836
 Python梦工厂 文章：8篇 阅读：11738
 Hive实战 文章：19篇 阅读：51903
 HBase实战 文章：9篇 阅读：11890
文章分类
最新评论