推荐模型
推荐模型的种类分为:
1.基于内容的过滤:基于内容的过滤利用物品的内容或是属性信息以及某些相似度定义,来求出与该物品类似的物品。
2.协同过滤:协同过滤是一种借助众包智慧的途径。它利用大量已有的用户偏好来估计用户对其未接触过的物品的喜好程度。其内在思想是相似度的定义。
在基于用户的方法的中,如果两个用户表现出相似的偏好(即对相同物品的偏好大体相同),那就认为他们的兴趣类似。
同样也可以借助基于物品的方法来做推荐。这种方法通常根据现有用户对物品的偏好或是评级情况,来计算物品之间的某种相似度。
3.矩阵分解:
3.1. 显式矩阵分解
例如我们可以得到多个用户对多部电影的评级的数据,这样我们就可以得到一个用户—电影评级的矩阵。
我们所得到的这个矩阵是稀疏的,假设得到的“用户—物品”矩阵的维度为U×I,我们需要对其进行降维,然后得到一个表示用户的U×k维矩阵和一个表示物品的k×I维矩阵。
要计算给定用户对某个物品的预计评级 :
只需要从用户因子矩阵和物品因子矩阵分别选取相应的行(用户因子向量)与列(物品因子向量),然后计算两者的点积即可
而对于物品之间相似度的计算,可以用最近邻模型中用到的相似度衡量方法。不同的是,这里可以直接利用物品因子向量,将相似度计算转换为对两物品因子向量之间相似度的计算
1.使用的是Spark-shell和Scala语言,同样需要把文件放在Hadoop文件系统中
启动Spark-shell
(在此网站可以下载u.data数据,https://grouplens.org/datasets/movielens/)
1 2 |
|
1 2 |
|
提取出前三个字段
1 |
|
使用ALS模型进行训练
1 2 |
|
1 2 |
|
1 |
|
结果,每个用户和每部电影都会有对应的因子数组(分别含943个和1682个因子)
1 2 3 4 5 6 7 8 |
|
1. 从MovieLens 100k数据集生成电影推荐
MLlib的推荐模型基于矩阵分解,因此可用模型所求得的因子矩阵来计算用户对物品的预计评级。
1 2 |
|
predict 函数同样可以以 (user, item) ID对类型的RDD对象为输入,这时它将为每一对都生成相应的预测得分。我们可以借助这个函数来同时为多个用户和物品进行预测。
要为某个用户生成前K个推荐物品 , 可借助 MatrixFactorizationModel 所提供的recommendProducts 函数来实现。该函数需两个输入参数: user 和 num 。其中 user 是用户ID,而 num 是要推荐的物品个数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
2. 检验推荐内容
读入电影数据,导入为Map[Int, String] 类型,即从电影ID到标题的映射
1 2 |
|
查看123对应的电影的名称
1 2 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
附录: 完整的idea项目代码,要引入maven依赖 <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-mllib_2.11</artifactId> <version>2.3.3</version> </dependency> package com.peigen /** * Created by peigen on 2019/7/8. * 推荐引擎相关概念概述: * 场景:1.可选项众多 2.偏个人喜好 * 1.基于内容的过滤: 利用物品的内容或是属性信息以及某些相似度定义,来求出与该物品类似的物品。 * 2.基于用户的协同过滤: 利用大量已有的用户偏好来估计用户对其未接触过的物品的喜好程度。内在思想是相似度的定义。 * 3.两者的得分取决于若干用户或是物品之间依据相似度所构成的集合,即最近邻模型。 * * 1.计算给定用户对某个物品的预计评级: 从用户因子矩阵取相应的行和物品因子矩阵取列,然后计算点积即可。 * 2.对于物品之间相似度的计算,可以利用最近邻模型中用到的相似度衡量方法。这里可直接将相似度计算转换成对两个物品因子之间相似度计算。 * * ALS实现原理:迭代求解一系列最小二乘回归问题,相互更新迭代到模型收敛,是一种求解矩阵分解问题的最优化方法。 */ import org.apache.log4j._ import org.apache.spark._ object Recommend { def main(args: Array[String]) { Logger.getLogger("org.apache.spark").setLevel(Level.WARN) Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF) val conf = new SparkConf() .setAppName("MovieLensALS").setMaster("local[5]") val sc = new SparkContext(conf) /**提取特征(影片 ID 星级 事件戳)*/ val rawData = sc.textFile("D:/test_data/ml-100k/u.data") println(rawData.first()) // val ratingsList_Tuple = sc.textFile("file:///home/raini/data/ml-10M/ratings.dat").map { lines => // val fields = lines.split("::") // (fields(0).toInt, fields(1).toInt, fields(2).toDouble, fields(3).toLong % 10) // } // ratingsList_Tuple.first // val rawRatings = rawData.map(_.split("\t").take(3)) println(rawRatings.first()) import org.apache.spark.mllib.recommendation.{ALS, Rating} val ratings = rawRatings.map { case Array(user, movie, rating) => Rating(user.toInt, movie.toInt, rating.toDouble)} println(ratings.first()) /**训练推荐模型*/ val rank = 50 //因子个数 val iteratings = 10 //迭代 val lambda = 0.01 //正则化参数 val model = ALS.train(ratings, rank, iteratings, lambda) // model.userFeatures // model.userFeatures.count() // model.productFeatures.count() /**使用推荐模型*/ //用户推荐(给定用户对 给定物品预计得分-点积) // org.apache.spark.mllib.recommendation.MatrixFactorizationModel val predictedRating = model.predict(789,123) println("predictedRating : " + predictedRating) val userID = 789 val K = 10 val topKRecs = model.recommendProducts(userID,K) println("topKRecs : " + topKRecs.mkString("\n")) /**检验推荐内容*/ val movies = sc.textFile("D:/test_data/ml-100k/u.item") val titles = movies.map(line => line.split("\\|").take(2)).map(array => (array(0).toInt, array(1))).collectAsMap() println(titles(123)) //keyBy创建键值对RDD,lookup只返回给定键值 val moviesForUser = ratings.keyBy(_.user).lookup(789) println(moviesForUser.size) //该用户评价过多少电影 //查看789用户评价最高的10部电影 moviesForUser.sortBy(-_.rating).take(10).map(rating => (titles(rating.product),rating.rating)).foreach(println) //查看给789用户推荐的前10部电影,sortBy 中的- 表示倒序 topKRecs.map(rating => (titles(rating.product), rating.rating)).foreach(println) } } |