案例:Spark基于用户的协同过滤算法
一 基于用户协同过滤简介
基于用户的协同过滤算法(user-based collaboratIve filtering)
基于用户的协同过滤算法是通过用户的历史行为数据发现用户对商品或内容的喜欢(如商品购买,收藏,内容评论或分享),并对这些喜好进行度量和打分。根据不同用户对相同商品或内容的态度和偏好程度计算用户之间的关系。在有相同喜好的用户间进行商品推荐。简单的说就是如果A,B两个用户都购买了x,y,z三本图书,并且给出了5星的好评。那么A和B就属于同一类用户。可以将A看过的图书w也推荐给用户B。
Spark MLlib的ALS
spark.ml目前支持基于模型的协作过滤,其中用户和产品由可用于预测缺失条目的一小组潜在因素来描述。spark.ml使用交替最小二乘(ALS) 算法来学习这些潜在因素。算法实现中spark.ml提供有以下参数:
- numBlocks是为了并行化计算而将用户和项目分割成的块的数量(默认为10)。
- rank是模型中潜在因子的数量(默认为10)。
- maxIter是要运行的最大迭代次数(默认为10)。
- regParam指定ALS中的正则化参数(默认为1.0)。
- implicitPrefs 显示的反馈ALS(true,显示的表示偏好程度)或者隐式的反馈ALS(false隐式指定偏好)。默认是false,显示反馈ALS
- alpha 偏好观察中置信度(可理解为一个系数),用于隐式反馈ALS。默认值是1.
- nonnegative指定是否对最小二乘使用非负约束(默认为false)。
注意:ALS基于DataFrame的API目前仅支持用户和项目ID为整数。用户和项目ID列支持其他数字类型,但ID必须在整数值范围内。
显式与隐式反馈
基于矩阵分解的协作过滤的标准方法将用户条目矩阵中的条目视为用户对该项目的显式偏好,例如,用户给电影的评级。
在许多真实世界的使用情况中,通常只能访问隐式反馈(例如,观看,点击,购买,喜欢,分享等)。根本上讲,这种方法不是根据用户直接评分建模,而是根据用户的行为(点击次数,停留时间),将其视为数字,代表用户对电影的可能喜欢程度。然后,这些数字与观察到的用户偏好的置信度相关,而不是与物品的显式评分。然后该模型将尝试找出可以用来预测用户对于某一项目的预期偏好的潜在因子。
正则化参数
调整的正则化参数regParam,是根据用户在更新用户因子时产生的评分数或者物品在更新物品因子时收到的评分数来解决每个最小二乘问题。这种方法被命名为“ALS-WR”,并在“Large-Scale Parallel Collaborative Filtering for the Netflix Prize ”文章中进行了讨论。它对regParam数据集规模的依赖较小,因此我们可以将从采样子集学习到的最佳参数应用于整个数据集,并期望有相似的性能。
冷启动策略
使用ALSModel进行预测时,测试数据集中的用户和/或项目在训练模型期间不存在是很常见的。这通常发生在两种情况下:
- 在生产中,对于没有评级历史记录且未进行模型训练的新用户或物品(这是“冷启动问题”)。
- 在交叉验证过程中,数据分为训练集和评估集。当Spark中的使用简单随机拆分为CrossValidator或者TrainValidationSplit,它实际上是非常普遍遇到的评估集不是在训练集中的用户和/或项目。
默认情况,Spark在ALSModel.transform用户和/或项目因素不存在于模型中时分配NaN预测。这在生产系统中可能是有用的,因为它表名一个新的用户或项目,因此系统可以作为预测的一个后备决定。
然而,这在交叉验证期间是不希望的,因为任何NaN预测值都将影响NaN评估度量的结果(例如,在使用时RegressionEvaluator)。这使得模型选择变得不可能。Spark允许用户将coldStartStrategy参数设置为“drop”,以便删除DataFrame包含NaN值的预测中的任何行。
注意:目前支持的冷启动策略是“nan”(上面提到的默认行为)和“drop”。未来可能会支持进一步的策略。
MovieLens电影基于用户推荐
在以下示例中,我们将从MovieLens数据集(https://grouplens.org/datasets/movielens/)中加载评分数据 ,每行由用户,电影,评分和时间戳组成。然后,我们训练一个ALS模型,默认情况下,这个模型的评分是明确的(implicitPrefs是false)。我们通过测量评级预测的均方根误差来评估推荐模型。
import org.apache.spark.ml.evaluation.RegressionEvaluator
import org.apache.spark.ml.recommendation.ALS
import org.apache.spark.sql.SparkSession
object ALSExample {
case class Rating(userId: Int, movieId: Int, rating: Float, timestamp: Long)
def parseRating(str: String): Rating = {
val fields = str.split("::")
assert(fields.size == 4)
Rating(fields(0).toInt, fields(1).toInt, fields(2).toFloat, fields(3).toLong)
}
def main(args: Array[String]) {
val spark = SparkSession
.builder
.appName("ALSExample")
.getOrCreate()
import spark.implicits._
// $example on$
val ratings = spark.read.textFile("file:///opt/modules/spark-2.2.0/data/mllib/als/sample_movielens_ratings.txt").map(parseRating).toDF()
//将数据集切分为训练集和测试集
val Array(training, test) = ratings.randomSplit(Array(0.8, 0.2))
//使用ALS在训练集数据上构建推荐模型
val als = new ALS().setMaxIter(5).setRegParam(0.01).setUserCol("userId").setItemCol("movieId").setRatingCol("rating")
val model = als.fit(training)
// 通过计算rmse(均方根误差)来评估模型
//为确保不获取到NaN评估参数,我们将冷启动策略设置为drop。
val predictions = model.transform(test)
val evaluator = new RegressionEvaluator().setMetricName("rmse").setLabelCol("rating").setPredictionCol("prediction")
val rmse = evaluator.evaluate(predictions)
println(s"Root-mean-square error = $rmse")
//每个用户推荐的前十个电影
val userRecs = model.recommendForAllUsers(10)
//每个电影推荐的十个用户
val movieRecs = model.recommendForAllItems(10)
userRecs.show()
movieRecs.show()
spark.stop()
}
}
如果评级矩阵是从另一个信息源(即它是从其他因子推断)得出,可以设置implicitPrefs以true获得更好的效果:
val als = new ALS()
.setMaxIter(5)
.setRegParam(0.01)
.setImplicitPrefs(true)
.setUserCol("userId")
.setItemCol("movieId")
.setRatingCol("rating")
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android编程实现XML解析与保存的三种方法详解
- 浅谈关于Android路由的实现
- Android中EditText禁止输入表情的实例代码
- Android仿微信右滑返回功能的实例代码
- 算法复现·推荐算法 | DeepFM for CTR Prediction
- Android 中Notification弹出通知实现代码
- Android编程实现添加低电流提醒功能的方法
- Android头像上传功能的实现代码(获取头像加剪切)
- Android自定义View画圆功能
- Android打包版本号设置方法
- Android编程实现获取系统内存、CPU使用率及状态栏高度的方法示例
- Android 6.0开发实现关机菜单添加重启按钮的方法
- 基于Socket.IO实现Android聊天功能代码示例
- Android 滑动监听的实例详解
- Android中使用ListView模拟微信好友功能