ALS算法介绍
https://blog.csdn.net/qq_42448606/article/details/109214713
原理是矩阵分解
数据集
选择的数据集是经典的movielens
http://files.grouplens.org/datasets/movielens/
并将其中的一部分数据分离出来用于下面模型训练和预测:资源已上传:需要下载请到如下链接:
代码中需要的数据
代码如下
package com.cjy.bigdata.spark.ml.ALS;
import com.cjy.bigdata.spark.ml.ALS.entity.MovieScore;
import org.apache.spark.api.java.function.MapFunction;
import org.apache.spark.ml.evaluation.RegressionEvaluator;
import org.apache.spark.ml.recommendation.ALS;
import org.apache.spark.ml.recommendation.ALSModel;
import org.apache.spark.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author cjy
* @description: ALS基于交替最小二乘法的协同过滤算法
* 数据集:http://files.grouplens.org/datasets/movielens/
* @date: 2022$ 07/06$
*/
public class ALSMovieRecommend {
public static void main(String[] args) {
SparkSession sparkSession = SparkSession.builder().appName("BatchAnalysis").master("local[*]")
.config("spark.sql.shuffle.partitions", "4")//本次测试时将分区数设置小一点,实际开发中可以根据集群规模调整大小,默认200
.getOrCreate();
Dataset<String> dataset = sparkSession.read().textFile("datas/u.data");
//得到需要分析的dataset
Dataset<MovieScore> movieScoreDataset = dataset.map((MapFunction<String, MovieScore>) line -> {
String[] strings = line.split("\t");
return new MovieScore(Integer.valueOf(strings[0]), Integer.valueOf(strings[1]), Double.valueOf(strings[2]));
}, Encoders.bean(MovieScore.class));
//new StructType(new StructField[]{new StructField("name", DataTypes.StringType,true),})
//按照8:2的比例划分数据集
Dataset<MovieScore>[] datasets = movieScoreDataset.randomSplit(new double[]{0.8, 0.2},50);
Dataset<MovieScore> trainSet = datasets[0];
Dataset<MovieScore> testSet = datasets[1];
//构建ALS算法推荐模型并训练
ALS als = new ALS()
.setUserCol("userId")//设置用户id是哪一列
.setItemCol("movieId") //设置产品id是哪一列
.setRatingCol("score") //设置评分列
.setColdStartStrategy("drop") //设置冷启动,预测时处理未知或新用户/item的策略。这在交叉验证或生产场景中可能很有用,对于处理模型在训练数据中没有看到的用户/项目id。支持的值:“nan”、“drop”。
.setRank(15) //可以理解为Cm*n = Am*k X Bk*n 里面的k的值,矩阵的秩
.setMaxIter(10) //最大迭代次数
.setAlpha(1.0);//迭代步长
//.setRegParam(0.02);//正则化参数
//训练模型
ALSModel alsModel = als.fit(trainSet);
//模型评估,rmse均方误差(求差,开方,求平均,开根);
Dataset<Row> predictions = alsModel.transform(testSet);
predictions.show();
//创建误差评估器
RegressionEvaluator regressionEvaluator = new RegressionEvaluator()
.setMetricName("rmse")//设置要计算的误差名称,均方根误差 (sum((y-y')^2)/n)^0.5
.setLabelCol("score")//设置真实值是哪一列
.setPredictionCol("prediction");//设置预测值是哪一列
//对数据中的真实值和预测值进行误差计算
double rmse = regressionEvaluator.evaluate(predictions);
System.out.println("rmse为:" + rmse);
//模型评估,mae平均绝对误差(求差的绝对值,后平均,个人认为这个评估值更能表示所写模型);
regressionEvaluator.setMetricName("mae")//设置要计算的误差名称,mae
.setLabelCol("score")//设置真实值是哪一列
.setPredictionCol("prediction");//设置预测值是哪一列
//对数据中的真实值和预测值进行误差计算
double mae = regressionEvaluator.evaluate(predictions);
System.out.println("mae为:" + mae);
//可以得到分数的区间是0-5分,那么误差率可以求得为
System.out.println("平均绝对误差率" + (mae/5.0));
//使用测试集测试模型,给测试集中的每个用户推荐与其5个相关性最高的电影
Dataset<Row> rowDataset = alsModel.recommendForUserSubset(testSet, 5);
rowDataset.show(false);
//使用测试集测试模型,给测试集中的每个电影推荐与其相关性最高的5个用户
alsModel.recommendForItemSubset(testSet, 5).orderBy(functions.desc("movieId")).show(false);
//预测测试集中的每个用户给一个电影的评分
alsModel.transform(testSet).show();
//给指定用户推荐
List<MovieScore> data = new ArrayList<>();
data.add(new MovieScore(0,163,0.0));
Dataset<MovieScore> appoint = sparkSession.createDataset(data, Encoders.bean(MovieScore.class));
alsModel.recommendForUserSubset(appoint,5).show(false);
}
}
目前写的感觉只是简单的推荐,用到了其中的一个数据集,并没有对其他数据的关联关系进行操作。个人理解,ALS算法已经是很成熟了,因此如果训练模型的数据相关性越高,那么其推荐的准确率越高,因此构建相关性的数据处理是针对一种业务更换的解决方式,后续有深入学习再进行补充。