协作过滤通常用于推荐系统。这些技术旨在填补用户-项目关联矩阵中丢失的条目。spark.ml 目前支持基于模型的协同过滤,其中用户和项目通过一小组潜在因素来描述,可用于预测缺失的条目。spark.ml 使用 ALS(交替最小二乘法)算法来学习这些潜在因素。spark.ml 中的实现具有以下参数:
注意:用于 ALS 的基于 DataFrame(数据框)的 API 目前仅支持整数的用户和项目id。 用户和项目id的列支持其他数字类型,但是列中id的取值必须在整数值范围内。
基于矩阵分解的协同过滤的标准方法是将用户-项目关联矩阵中的元素视为用户对项目的显式偏好,例如用户对电影的评分。在现实世界中的许多用例中,通常只能接触到隐式的反馈(例如浏览,点击,购买,喜欢,分享等)。在 spark.ml 中使用基于隐式反馈数据集的协同过滤的方法来处理这些数据。实际上,这种方法不是直接对数据矩阵进行建模,而是将数据视为代表用户行为意愿强度的数字(例如点击的次数或某人累积观看电影的时间)。然后,这些数字与观察到的用户偏好的置信水平相关,而不是给予项目的明确评级。 然后,该模型尝试找到可用于预测用户对项目的预期偏好的潜在因素。
我们通过用户在更新用户因素中产生的评分,或产品在更新产品因素中收到的评分来求解每个最小二乘问题的规则化参数 regParam 。 这种方法被命名为“ ALS-WR ”(加权正则化交替最小二乘法),并在论文“ Large-Scale Parallel Collaborative Filtering for the Netflix Prize ”中进行了讨论。 它使 regParam 对数据集的规模依赖较少,因此我们可以将从采样子集学到的最佳参数应用于完整数据集,并期望能有相似的表现。
在以下示例中,我们从 MovieLens 数据集加载评分数据,每行由用户,电影,评分和时间戳组成。 然后,我们训练一个 ALS 模型,默认情况下假定评分是显式的( implicitPrefs 是 false )。 我们通过测量评级预测的 root-mean-square error(均方根误差)来评估推荐模型。
有关API的更多详细信息,请参阅 ALS Scala 文档。
import org.apache.spark.ml.evaluation.RegressionEvaluator import org.apache.spark.ml.recommendation.ALS 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) } val ratings = spark.read.textFile("data/mllib/als/sample_movielens_ratings.txt") .map(parseRating) .toDF() 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() .setMaxIter(5) .setRegParam(0.01) .setUserCol("userId") .setItemCol("movieId") .setRatingCol("rating") val model = als.fit(training) // Evaluate the model by computing the RMSE on the test data 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")
可以在 Spark repo 中的“examples/src/main/scala/org/apache/spark/examples/ml/ALSExample.scala”中查找完整的示例代码。
如果评分矩阵是来自于另一个信息来源(即从其他信号推断出来),您可以将 implicitPrefs 设置为 true 以获得更好的结果:
val als = new ALS() .setMaxIter(5) .setRegParam(0.01) .setImplicitPrefs(true) .setUserCol("userId") .setItemCol("movieId") .setRatingCol("rating")