代码实现如下:
使用电影数据集进行训练模型
package mllib.Collaborativefiltering
import org.apache.log4j.{Level, Logger}
import org.apache.spark.sql.SparkSession
import org.apache.spark.mllib.recommendation.{ALS, Rating}
import org.apache.spark.rdd.RDD
/**
* Created by win7 on 2018/10/23.
*
* 使用协同过滤实现spark mllib推荐功能
* 数据集:电影数据集
*
*/
object moivelensALStrain {
val numRecommender = 10
"""
|参数设置:
|numBlocks:是用于并行计算的块数(设置为-1以自动配置)。
|rank:是模型中潜在因子的数量。
|iterations:是要运行的ALS的迭代次数。ALS通常在20次或更少次迭代中收敛到合理的解决方案。
|lambda:指定ALS中的正则化参数。
|implicitPrefs:指定是使用显式反馈 ALS变体还是使用适用于隐式反馈数据的变量 。
|α:是适用于ALS的隐式反馈变体的参数,其控制偏好观察中的 基线置信度。
""".stripMargin
def main(args: Array[String]): Unit = {
//屏蔽日志
Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
val spark = SparkSession
.builder()
.appName(s"${this.getClass.getSimpleName}")
.master("local[4]")
.getOrCreate()
//加载数据
val data = spark.read.textFile("D:\\nobody\\src\\main\\scala\\mllib\\data\\u.data").distinct()
val ratings: RDD[Rating] = data.rdd.map(_.split("\t") match {
case Array(user, item, rate, time) => Rating(user.toInt, item.toInt, rate.toDouble)
})
// ratings.show(false)
val rank = 10
val numIterations = 10
val lambda = 0.01
val model = ALS.train(ratings, rank, numIterations, lambda)
"""
|模型评估
""".stripMargin
val usersProducts: RDD[(Int, Int)] = ratings.map { case Rating(user, product, rate) =>
(user, product)
}
//预测数据
val predictions = model.predict(usersProducts).map { case Rating(user, product, rate) =>
((user, product), rate)
}
//将真实分数与预测分数进行合并
val ratesAndPreds = ratings.map { case Rating(user, product, rate) =>
((user, product), rate)
}.join(predictions)
//计算均方差
val MSE = ratesAndPreds.map { case ((user, product), (r1, r2)) =>
val err = (r1 - r2)
err * err
}.mean()
println("Mean Squared Error = " + MSE)
"""
|模型保存及加载
""".stripMargin
/*model.save(spark.sparkContext,"D:\\nobody\\src\\main\\scala\\mllib\\data\\model")
val sameModel = MatrixFactorizationModel.load(spark.sparkContext,"D:\\nobody\\src\\main\\scala\\mllib\\data\\model")*/
}
}
加载训练好的模型进行推荐
import org.apache.log4j.{Level, Logger}
import org.apache.spark.mllib.recommendation.{MatrixFactorizationModel, Rating}
import org.apache.spark.sql.SparkSession
import org.jblas.DoubleMatrix
import scala.collection.Map
/**
* Created by win7 on 2018/10/23.
*
* 加载协同过滤模型进行推荐
*/
object loadmodel {
def main(args: Array[String]): Unit = {
Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
val spark = SparkSession
.builder()
.appName(s"${this.getClass.getSimpleName}")
.master("local[4]")
.getOrCreate()
val model = MatrixFactorizationModel.load(spark.sparkContext, "D:\\nobody\\src\\main\\scala\\mllib\\data\\model")
"""
|各种推荐方式
|1.根据用户推荐物品
|2.根据用户推荐用户
|3.根据用户推荐用户
|4.根据物品推荐物品
""".stripMargin
println("-----------------基于用户推荐--------根据用户推荐物品及根据物品推荐用户---------")
val movies = spark.sparkContext.textFile("D:\\nobody\\src\\main\\scala\\mllib\\data\\u.item")
//电影id 电影名称
val titles:Map[Int,String] = movies.map(line => line.split("\\|").take(2)).map(array => (array(0).toInt, array(1))).collectAsMap()
//给111用户推荐 10部电影
"""
|为单个用户推荐商品
|指定 用户和推荐个数
""".stripMargin
val userId = 111
val n = 10
val topn = model.recommendProducts(userId, n)
// println(topn.mkString("\n"))
"""
|给所有用户推荐商品
|指定推荐个数即可
""".stripMargin
//给所有用户进行推荐
model.recommendProductsForUsers(10).flatMap(x => {
val user = x._1.toString
val rat = x._2
var res = List[(String, String, String)]()
for (r <- rat) {
res = res :+ (user, r.product + ",", titles(r.product) + "," + r.rating)
}
res
})//.foreach(println)
"""
|给产品推荐用户 两种方式
|指定商品id 和 推荐用户个数
""".stripMargin
model.recommendUsers(451,10)//.foreach(println)
"""
|给所有产品推荐用户
|指定推荐个数即可
""".stripMargin
model.recommendUsersForProducts(10)
"""
|根据物品推荐物品
|
""".stripMargin
"""
|根据某物品推荐物品
|基于物品推荐物品的,可以将推荐结果事先保存到es中,大数据系统直接取检索,即可得到推荐的结果
|推荐没天进行更新一次
""".stripMargin
val ss: String = similarProduct(model,230,10).toList.mkString(":::")
println(ss)
"""
|找到所有物品的最类似的物品
|与本身最相近的还是本身,所以如果取前10个,N需要设置为11
""".stripMargin
titles.map(tuple=>{
val recomList = similarProduct(model,tuple._1,10)
(tuple._1,recomList.toList.mkString(":::"))
})//.foreach(println)
}
/**
* 计算余弦相似度
* @param vec1
* @param vec2
* @return
*/
def cosineSimilarity(vec1: DoubleMatrix, vec2: DoubleMatrix): Double = {
vec1.dot(vec2) / (vec1.norm2() * vec2.norm2())
}
/**
* 得到用户因子和物品因子
*/
def obtainFeatures(model: MatrixFactorizationModel) = {
val userFeatures = model.userFeatures
val productFeatures = model.productFeatures
(userFeatures, productFeatures)
}
/**
* 求某个物品与各个物品的余弦相似度
*/
def productCosineSimilarity(model: MatrixFactorizationModel, itemId: Int) = {
val itemFactor = model.productFeatures.lookup(itemId).head
val itemVector = new DoubleMatrix(itemFactor)
val sims = model.productFeatures.map {
case (id, factor) => {
val factorVector = new DoubleMatrix(factor)
val sim = this.cosineSimilarity(factorVector, itemVector)
(id, sim)
}
}
sims
}
/**
* 求与某个物品相似的前N的物品
*/
def similarProduct(model: MatrixFactorizationModel, itemId: Int, N: Int = 10) = {
val sims = this.productCosineSimilarity(model, itemId)
val sortedSims = sims.top(N)(Ordering.by { x => x._2})
sortedSims
}
}