spark机器学习之als

来源:互联网 发布:linux ioctl函数详解 编辑:程序博客网 时间:2024/04/25 12:49

今天分析一下als算法在spark mlib中的相关应用,关于原理性的东西,还是不多做介绍,als本身是协同过滤算法的一种,08年以来也是使用最频繁的协同过滤算法了。主要的原理性东西,推荐这篇博客:

http://blog.csdn.net/antkillerfarm/article/details/53734658

本文章在这里主要还是介绍als算法在spark mlib中的应用,以及在构建rating和插入数据库的一些方法。

上代码

val trainingData = sc.textFile("/usr/local/soft/data/rating.csv")

首先获取数据来源,目前我们通过数据文件的方式进行获取,数据文件内的数据格式如下:

2538,2366,42538,2430,12538,2724,12538,2934,12538,3132,12540,1564,12540,2366,42540,2430,12540,2632,12540,2642,22540,2644,1

其中的每一条记录都是一个rating结构,第一个元素可以看作是用户的id,第二个元素可以看作是内容的id,第三个元素是score,这个score的获取是用户对内容得分的情况,这个得分可以通过多种进行获取。例如:通过用户点击的次数、用户直接对内容的打分等等。
读取完数据后,开始对读取的数据进行处理:

val train = trainingData.map { x => x.split(",") }val traingRDD = train.map(x => Rating(x(0).toInt, x(1).toInt, x(2).toDouble))

将获取的数据进行逗号分隔,并且将分隔后的数据,转化为rating的结构。以便后边交给模型进行处理。

val model = ALS.train(traingRDD, 1, 10)

其实上述代码是整个代码的核心部分,将我们准备好的数据交给算法进行处理,其中后边参数的设置可以查看spark mlib的api

deftrain(ratings: RDD[Rating], rank: Int, iterations: Int): MatrixFactorizationModelTrain a matrix factorization model given an RDD of ratings given by users to some products, in the form of (userID, productID, rating) pairs. We approximate the ratings matrix as the product of two lower-rank matrices of a given rank (number of features). To solve for these features, we run a given number of iterations of ALS. The level of parallelism is determined automatically based on the number of partitions in ratings.ratingsRDD of (userID, productID, rating) pairsranknumber of features to useiterationsnumber of iterations of ALS (recommended: 10-20)Annotations@Since( "0.8.0" 

两个参数分别是算法使用的特征值和算法迭代的次数,通过调整迭代次数,可以选择更加合理的参数,使得MSE可以达到最小值。

val lambda = List(0.001, 0.005, 0.01, 0.015, 0.02, 0.1)    //迭代次数val iteration = List(10, 20, 30, 40)for (l <- lambda; i <- iteration) {      val model = ALS.train(traingRDD, rank, i, l)      val predict = model.predict(training2).map {        case Rating(userid, movieid, rating) => ((userid, movieid), rating)      }val predictAndFact = predict.join(test2)val MSE = predictAndFact.map {        case ((user, product), (r1, r2)) =>          val err = r1 - r2          err * err      }.mean()

通过迭代以上连参数,可以得到不同MSE的值。
项目中用户量级不多,因此我们离线每小时将用户的推荐结果存入mysql。在此我们就需要对如何对全部用户进行存储进行相关的设计。

val allusers = train.map { x => x(0).toInt }.distinct().toLocalIterator//获取全部用户
 while (allusers.hasNext) {      val user = allusers.next()      if (user.equals(0)) {        val rec = model.recommendProducts(user, limit)        //将rec写成dataframe        print("recommend user is " + rec(1).user + "," + rec(2).user)        print("recommend rating is " + rec(1).rating + "," + rec(2).rating)        print("recommend product is " + rec(1).product + "," + rec(2).product)        writeRecResultToMysql(rec, sqlContext, sc)      } else {        val rec = model.recommendProducts(user, limit)        //将rec写成dataframe        print("recommend user is " + rec(1).user + "," + rec(2).user)        print("recommend rating is " + rec(1).rating + "," + rec(2).rating)        print("recommend product is " + rec(1).product + "," + rec(2).product)        writeRecResultToMysql(rec, sqlContext, sc)      }    }

上述代码做的判断,是对是否是游客的判断,对整个算法逻辑来讲可以先忽略。

 def writeRecResultToMysql(uid: Array[Rating], sqlContext: SQLContext, sc: SparkContext) {      val uidString = uid.map(x => x.user.toString() + ","        + x.product.toString() + "," + x.rating.toString())      import sqlContext.implicits._      val uidDFArray = sc.parallelize(uidString)      val uidDF = uidDFArray.map(x => x.split(",")).map(x => Result(x(0).trim().toInt, x(1).trim.toInt, x(2).trim().toDouble)).toDF      uidDF.write.mode(SaveMode.Append).jdbc(jdbcURL, recResultTable_als, prop)    }

通过调用方法writeRecResultToMysql将得到的推荐数据写入mysql,建议采用追加的模式,即mode(SaveMode.Append)。
以上,就是als在mlib当中简单的应用,其实在参数选取等等方面还有一些优化和自动化的东西,在后续再与大家进行分享。

原创粉丝点击