spark机器学习:使用ALS完成商品推荐

ALS(Alternating Least Squares)是一种广泛使用的推荐系统算法,特别用于协同过滤(Collaborative Filtering)任务。在 Apache Spark 中,ALS 被实现为 org.apache.spark.ml.recommendation.ALS 类,适用于大规模数据集,并能够有效地处理稀疏矩阵,常用于推荐引擎。


ALS 算法的基本思想

ALS 的主要思想是:

  1. 分解矩阵:ALS 通过将用户-项目评分矩阵分解为两个低秩矩阵——用户特征矩阵和项目特征矩阵。这使得可以通过用户和项目之间的特征相似度来预测评分。

  2. 交替优化:该算法交替地固定用户特征矩阵和项目特征矩阵,并通过最小化损失函数(通常是均方误差)来优化这两个矩阵。具体的优化步骤是:

    • 在固定项目特征矩阵的情况下,优化用户特征矩阵。
    • 然后在固定用户特征矩阵的情况下,优化项目特征矩阵。
    • 重复以上步骤直到收敛。

在Spark 中使用 ALS

在 Spark 中,ALS 提供了一种简单而高效的方式来构建推荐模型。以下是使用 Spark 中的 ALS 的基本步骤:

  1. 导入必要的库

    import org.apache.spark.ml.recommendation.ALS
    import org.apache.spark.sql.SparkSession
    
  2. 创建 Spark 会话

    val spark = SparkSession.builder()
        .appName("ALSExample")
        .getOrCreate()
    
  3. 准备数据

    数据应包含用户 ID、项目 ID 和评分,通常以 DataFrame 格式存储。

    val ratings = Seq(
        (0, 0, 4), 
        (0, 1, 2),
        (1, 0, 5), 
        (1, 1, 1)
    ).toDF("userId", "itemId", "rating")
    
  4. 构建 ALS 模型

    val als = new ALS()
        .setUserCol("userId")
        .setItemCol("itemId")
        .setRatingCol("rating")
        .setColdStartStrategy("drop") // 保证对待没有评分的预测结果的处理
        .setRank(10) // 设定特征向量的维度
        .setMaxIter(10) // 最大迭代次数
    
    val model = als.fit(ratings)
    
  5. 生成推荐

    可以使用模型生成用户和项目的推荐。

    val userRecs = model.recommendForAllUsers(5) // 为所有用户推荐 5 个项目
    val itemRecs = model.recommendForAllItems(5) // 为所有项目推荐 5 个用户
    

ALS实践练习

数据展示:
三列数据分别为用户 ID、物品 ID 和评分

1,1,5.0
1,2,1.0
1,3,5.0
1,4,1.0
2,1,5.0
2,2,1.0
2,3,5.0
2,4,1.0
3,1,1.0
3,2,5.0
3,3,1.0
3,4,5.0
4,1,1.0
4,2,5.0
4,3,1.0
4,4,5.0

在hdfs文件系统,创建目录,名为mymllib5,并将linux上的myrating文件数据,上传到hdfs

hadoop fs -mkdir /mymllib5
hadoop fs -put /myrating /mymllib5


启动spark-shell

spark-shell

为了执行协同过滤操作,需要首先导入执行统计所依赖的包

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.mllib.recommendation.ALS
import org.apache.spark.mllib.recommendation.MatrixFactorizationModel
import org.apache.spark.mllib.recommendation.Rating

读取hdfs上的myrating文本文件

val data = sc.textFile("hdfs://192.168.88.161:8020/mymllib5/myrating")


把数据转化成rating类型,即[Int, Int, Double]的RDD;

val ratings = data.map(_.split(",") match {  
	case Array(user, item, rate) =>  
	Rating(user.toInt, item.toInt, rate.toDouble)  
	})  

检查一下数据格式是否符合要求

ratings.foreach{x => println(x)}


划分训练集和测试集,比例分别是0.8和0.2。

val splits = ratings.randomSplit(Array(0.8, 0.2))

将80%作为训练数据集

val training = splits(0)

将20%作为测试数据集

val test = splits(1)


指定参数值,然后使用ALS训练数据建立推荐模型:

val rank = 10
val numIterations = 10
val model = ALS.train(training, rank, numIterations, 0.01)


使用训练好的推荐模型对用户商品进行预测评分,得到预测评分的数据集

val testUsersProducts = test.map { case Rating(user, product, rate) => (user, product) }

使用训练好的推荐模型对用户商品进行预测评分,得到预测评分的数据集:

val predictions =
    model.predict(testUsersProducts).map { case Rating(user, product, rate) =>((user, product), rate)
	}


将真实评分数据集与预测评分数据集进行合并。这里,Join操作类似于SQL的inner join操作,返回结果是前面和后面集合中配对成功的,过滤掉关联不上的。

val ratesAndPreds = test.map { case Rating(user, product, rate) => ((user, product), rate) }.join(predictions)

我们把结果输出,对比一下真实结果与预测结果:

ratesAndPreds.foreach(println)

查看输出效果:

比如,第一条结果记录((1,4),(1.0,2.0765385175171436))中,(1,4)分别表示1号用户和4号商品,而1.0是实际的估计分值,2.0765385175171436是经过推荐的预测分值。


当然,我们也可以针对于某一个人进行预测,对比结果。

val result = model.recommendProducts(2, 1)
result.foreach(println)


然后计算均方差,这里的r1就是真实结果,r2就是预测结果:

val MSE = ratesAndPreds.map { case ((user, product), (r1, r2)) => 
	    val err = (r1 - r2) 
	    err * err 
	}.mean() 

把输出结果打印出来:

println("Mean Squared Error = " + MSE)

输出效果:
看到打分的均方差值为1.44左右


posted @ 2024-11-28 15:16  你这过氧化氢掺水了  阅读(48)  评论(0编辑  收藏  举报