基于矩阵分解的推荐算法(评分数据集中,并不是每个用户都对每个产品进行过评分,所以这个矩阵往往是很稀疏的【所以更应该多注意过拟合的问题】,也就是说用户i对产品j的评分很多地方是空的,ALS所做的事情就是将这个稀疏矩阵通过一定的规律填满,这样就可以从矩阵中得到任意一个user对任意一个product的评分,然后以此为据做推荐。所以说,ALS算法的核心就是:打分矩阵是近似低秩的。换句话说,打分矩阵A(m∗n)”可以由“用户喜好特征矩阵U(m∗k)”和“产品特征矩阵V(n∗k)”的乘积。
显示反馈与隐式反馈(显式数据的数值代表偏好,隐式数据【无正面的直接表达用户喜好情况的数据】的数值代表了置信等级(confidence level))
##学习中(领悟)
// scalastyle:off println
package org.apache.spark.examples.ml
// $example on$
import org.apache.log4j.{Level, Logger}
import org.apache.spark.ml.evaluation.RegressionEvaluator
import org.apache.spark.ml.recommendation.ALS
// $example off$
import org.apache.spark.sql.SparkSession
object ALSExample {
// $example on$
/** 当你声明了一个 case class(样例类)时,scala会帮助我们做下面几件事情:
1 构造器中的参数如果不被声明为var的话,它默认的话是val类型的,但一般不推荐将构造器中的参数声明为var
2 自动创建伴生对象,同时在里面给我们实现子apply方法,使得我们在使用的时候可以不直接显示地new对象
3 伴生对象中同样会帮我们实现unapply方法,从而可以将case class应用于模式匹配
4 实现自己的toString、hashCode、copy、equals方法
*/
case class Rating(userId: Int, movieId: Int, rating: Float, timestamp: Long)
// 数据示例:0::2::3::1424380312
def parseRating(str: String): Rating = {
val fields = str.split("::")
// assert() 或 assume() 方法在对中间结果或私有方法的参数进行检验,不成功则抛出 AssertionError 异常
assert(fields.size == 4)
// 返回分割好的Rating对象,注意用户Id列以及产品id列,必须是整数(如果是其他数值类型,只要在整形范围内,都会转为integers)
Rating(fields(0).toInt, fields(1).toInt, fields(2).toFloat, fields(3).toLong)
}
// $example off$
def main(args: Array[String]) {
Logger.getLogger("org.apache.hadoop").setLevel(Level.ERROR)
Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
val spark = SparkSession
.builder
.master("local")
.appName("ALSExample")
.getOrCreate()
import spark.implicits._
// $example on$
val ratings = spark.read.textFile("data/mllib/als/sample_movielens_ratings.txt")
.map(parseRating)
.toDF()
ratings.printSchema()
ratings.show(5)
// 切分训练集和测试集
val Array(training, test) = ratings.randomSplit(Array(0.8, 0.2))
// Build the recommendation model using ALS on the training data
val als = new ALS()
.setRank(8) // 对应ALS模型中的因子个数,即矩阵分解出的两个矩阵的新的行/列数,即A≈UVT,k<<m,n中的k。
.setMaxIter(20) // 默认10
.setRegParam(0.01) // 正则化参数
.setImplicitPrefs(true) // 使用隐式反馈
.setUserCol("userId")
.setItemCol("movieId")
.setRatingCol("rating")
val model = als.fit(training)
// 通过计算测试集上的均方根误差来评估模型
// transform操作会增加一个prediction列
val predictions = model.transform(test)
println("=================predictions")
predictions.printSchema()
predictions.show(7)
val evaluator = new RegressionEvaluator()
.setMetricName("rmse")
.setLabelCol("rating")
.setPredictionCol("prediction")
val rmse = evaluator.evaluate(predictions)
println(s"Root-mean-square error = $rmse")
// $example off$
spark.stop()
}
}
// scalastyle:on println
##学习后(实操)
TODO
##总结
TODO
##参考