一.spark ml 协同过滤推荐算法
相似度算法
在Spark MLlib中提供了余弦相似度的分布式实现,org.apache.spark.mllib.linalg.distributed包中的IndexedRowMatrix是一个分布式矩阵类,其中提供了一个columnSimilarities方法用于计算该矩阵各列之间的余弦相似度。
预测值计算:采用加权求和的方法计算预测值.
Step 1:读取用户评分数据,设用户数为U,物品数目为I,将数据转换为以用户为行,物品为列的二维矩阵R,R维度为(U×I)。矩阵的每一个数据表示某个用户对特定物品的评分。
Step 2:计算R每列之间的相似度,可以得到维度(I×I)的矩阵S。S(i,j)表示物品i和物品j之间的相似度。
Step 3:使用预测值计算公式计算用户对未评分物品的预测评分。得到预测评分矩阵P,P维度为(U×I),P(i,j) 表示用户i对物品j的预测评分。
Step 4:对用户i进行推荐。找出P的第i行中评分最高的前K个物品推荐给用户。K是需要推荐的物品数量。
二.
关于官方例子:
官方例子是用户-电影数据
很多人想把例子copy过来试试,却不知道源数据是什么样子的。方法:spark-2.3.1-bin-hadoop2.7.tar 这个包大家很熟悉,解压后里面有很多目录,data\mllib目录下就有所有的源数据。官方的例子包括数据都是最优的,随便训练效果都很好,实际数据很糟糕。
三.
下边例子,我训练的是用户-主题,做的是某款软件上的主题推荐。
最终代码没有放上,这只是最开始的demo。
import org.apache.spark.ml.evaluation.RegressionEvaluator
import org.apache.spark.ml.recommendation.ALS
import org.apache.spark.sql.SparkSession
import org.apache.spark.storage.StorageLevel
object user_theme_model {
case class Rating(userId: Int, movieId: Int, rating: Float, timestamp: Long)
def parseRating(str: String): Rating = {
val fields = str.split("\001")
assert(fields.size == 6)
Rating(fields(1).toInt, fields(3).toInt, fields(4).toFloat, fields(5).toLong)
}
def main(args: Array[String]) {
val spark = SparkSession
.builder
.appName("user_theme_model")
//.master("local[4]")
.getOrCreate()
import spark.implicits._
val inputdata = args(0).toString
val outputdata = args(1).toString
val MaxIter = args(2).toInt
val RegParam = args(3).toFloat
// $example on$
val ratings = spark.read.textFile(inputdata).map(parseRating).toDF()
// 筛选出安装主题数大于N的用户,有大部分用户只安装了一个主题,特征太少,干掉了。
ratings.createOrReplaceTempView("input_data")
val result_valuse = spark.sql("SELECT uts.userId,uts.movieId,uts.rating,uts.timestamp from(SELECT userId from input_data GROUP BY userId HAVING count(userId)>4) TABLE1 join input_data uts on (uts.userId = TABLE1.userId)")
val ratings2 = result_valuse.toDF()
ratings2.show()
//将数据集切分为训练集和测试集
val Array(training, test) = ratings2.randomSplit(Array(0.9, 0.1))
//使用ALS在训练集数据上构建推荐模型
val als = new ALS()
.setMaxIter(MaxIter)
.setRegParam(RegParam)
.setUserCol("userId")
.setItemCol("movieId")
.setRatingCol("rating")
val model = als.fit(training)
//为确保不获取到NaN评估参数,我们将冷启动策略设置为drop。
model.setColdStartStrategy("drop")
val predictions = model.transform(test)
// 通过计算rmse(均方根误差)来评估模型
val evaluator = new RegressionEvaluator()
.setMetricName("rmse")
.setLabelCol("rating")
.setPredictionCol("prediction")
val rmse = evaluator.evaluate(predictions)
println(s"Root-mean-square error = $rmse")
//推荐前100个主题
val userRecs = model.recommendForAllUsers(100)
val dataout = userRecs.rdd.map(x => x.get(0) + "\001" + x.get(1))
dataout.saveAsTextFile(outputdata)
//userRecs.show()
spark.stop()
}
}
四.结果,我入hive了
有兴趣可以加我的大数据、数据分析、爬虫群:
《453908562》