推荐系统之——ALS交替最小二乘法建立推荐模型

一、背景:

在电子商务、社交媒体等领域,推荐系统已成为提升用户体验和平台价值的关键技术。推荐系统通过分析用户的行为数据,向用户推荐其可能感兴趣的内容或商品。ALS算法作为一种高效的矩阵分解算法,被广泛应用于推荐系统中,用于建立推荐模型。        

推荐算法总的来说分为四大类:

1.基于关联规则的推荐(Association Rule)

        直观易懂,算法原理非常简单,不涉及任何矩阵、导数等。

        适用于交易的信息数据:购物篮分析等等。

        能够发现数据中隐藏的、不易察觉的关联关系,如“购买A商品的客户也倾向于购买B商品”。

2.基于内容的推荐(Content-based)

        比较内容相似度,进行推荐

        对于新用户或新物品,只要有足够的内容信息,就可以进行推荐。

        在网站没有多少客户的时候,可以使用此算法

3.基于人口统计学的推荐(Demographic)

        按照用户标签进行推荐

        用户可以添加或修改标签,增加与系统的互动。

4.基于协同过滤的推荐(Collaborative Filter) :CF推荐

        基于用户协同过滤推荐(User-based):CF-U

        基于物品协同过滤推荐(Item-based):CF-I

        个性化程度高,能够基于用户的历史行为和相似用户的行为进行推荐

        能够处理非结构化的复杂对象,如音乐、电影等。

二、ALS(Alternating Least Squares)交替最小二乘法:

协同过滤算法:

协同过滤算法,是最经典,最常用的推荐算法。通过分析用户兴趣,在用户群中找到指定用户的相似用户,综合这些相似用户对某一信息的评价形成系统关于该指定用户对此信息的喜好程度预测

Spark MLlib支持ALS(Alternating Least Squares)交替最小二乘法属于协同过滤算法的一种:通过观察所有用户给产品的评价来判断每个用户的喜好,并向用户推荐适合的产品,也可以把某一个商品推进给多个用户。

算法{数据}:用户User对产品Prodect评价==rating==

算法{功能}:

功能1:预测用户对某个产品的喜好,比如张三对某个电影喜好,以评分形式表示

功能2:给某个用户推荐可能喜好的N部电影(TopKey)

功能3:为某部电影推荐可能喜欢用户(TopKey)

实现协同过滤,需要完成以下步骤:

(1)收集用户偏好

(2)找到相似的用户或物品

(3)计算推荐

ALS算法思想:

第一步,初始化因子矩阵:U0

第二步,依据X矩阵求取另外一个因子矩阵

第三步,交替求去另外因子矩阵,知道抵达迭代次数或满足收敛条件终止。

三、ALS算法推导:

1、矩阵分解:

对于 R(m*n)的矩阵,ALS旨在找到两个低阶矩阵U(m*k) 和 矩阵 V(n*k)来近似逼近R(m*n)

即:

大矩阵:R(n*m)其中n表示用户量、m表示物品量因子(Factorization)矩阵:
用户因子矩阵User:U(n*k),其中n表示用户量,k表示维度,矩阵列个数
物品因子矩阵Item/Product:V(k*m),其中m表示物理量,k表示维度,矩阵行个数
K值称为秩rank,需要用户训练模型时,进行指定,属于超参数,通常设置为5、10、20等

2、损失函数:

为了找到便低秩矩阵U和V尽可能地迈近R,需要最小化下面的平方误差损失函数:

3、L2正则化:

损失函数一般需要加入正则化项来避免过拟合等问题,使用L2正则化,所以上面的公式改造为:

        其中λ是正则化项的系数。

        此时协同过滤就成功转化成了一个优化问题。由于变量u和v耦合到一起,这个问题并不
好求解,所以引入 ALS,也就是说可以先固定V(例如随机初始化 U),然后利用公式(2)先
求解U,然后固定 U,再求解 V,如此交替往复直至收敛,即所谓的交替最小二乘法求解法。

 

4、交替求解:

固定 V 求解U,对公式进行求导化简,可得:

同理,固定 U 求解 V,对公式进行求导化简,可得:

四、基于RDD构建ALS推荐模型:

第一:ALS,算法实现有两个方法{train} 和 {trainImpllicit}

        当用户对物品评价为显式的调用{train}方法训练模型

        当用户对物品评价为隐式的则调用{trainImplicit}方法训练模型

第二:Rating,样例类,用于封装用户对物品的评价。

第三:MatrixFactorizationModel,将数据放入ALS算法训练获取的模型,就是存储两个因子矩阵  

接下来让我们使用ALS构建一个电影推荐模型:

整个{电影推荐模型构建}思路如下:

第一步:将用户对电影评价数据封装至Rating对象中

第二步:将数据集中到ALS算法,训练获取模型MatrixFactorizationModel

第三步:使用模型预测和推荐

代码如下:
 

/**
 * 使用MovieLens 电影评分数据集,调用Spark MLlib 中协同过滤推荐算法ALS建立推荐模型:
 * -a. 预测 用户User 对 某个电影Product 评价
 * -b. 为某个用户推荐10个电影Products
 * -c. 为某个电影推荐10个用户Users
 */
object SparkAlsRmdMovie {
	
	def main(args: Array[String]): Unit = {
		
		// TODO: 1. 构建SparkContext实例对象
		val sc: SparkContext = {
			// a. 创建SparkConf对象,设置应用相关配置
			val sparkConf = new SparkConf()
				.setMaster("local[2]")
				.setAppName(this.getClass.getSimpleName.stripSuffix("$"))
			// b. 创建SparkContext
			val context = SparkContext.getOrCreate(sparkConf)
			// 设置检查点目录
			context.setCheckpointDir(s"datas/ckpt/als-ml-${System.nanoTime()}")
			// c. 返回
			context
		}
		
		// TODO: 2. 读取 电影评分数据
		val rawRatingsRDD: RDD[String] = sc.textFile("datas/als/ml-100k/u.data")
		println(s"Count = ${rawRatingsRDD.count()}")
		println(s"First: ${rawRatingsRDD.first()}")
		
		// TODO: 3. 数据转换,构建RDD[Rating]
		val ratingsRDD: RDD[Rating] = rawRatingsRDD
			// 过滤不合格的数据
			.filter(line => null != line && line.split("\\t").length == 4)
			.map{line =>
				// 字符串分割
				val Array(userId, movieId, rating, _) = line.split("\\t")
				// 返回Rating实例对象
				Rating(userId.toInt, movieId.toInt, rating.toDouble)
			}
		// 划分数据集为训练数据集和测试数据集
		val Array(trainRatings, testRatings) = ratingsRDD.randomSplit(Array(0.9, 0.1))
		
		// TODO: 4. 调用ALS算法中显示训练函数训练模型
		// 迭代次数为20,特征数为10
		val alsModel: MatrixFactorizationModel = ALS.train(
			ratings = trainRatings, // 训练数据集
			rank = 10, // 特征数rank
			iterations = 20 // 迭代次数
		)
		
		// TODO: 5. 获取模型中两个因子矩阵
		/**
		 * 获取模型MatrixFactorizationModel就是里面包含两个矩阵:
		 * -a. 用户因子矩阵
		 *         alsModel.userFeatures
		 * -b. 产品因子矩阵
		 *         alsModel.productFeatures
		 */
		// userId -> Features
		val userFeatures: RDD[(Int, Array[Double])] = alsModel.userFeatures
		userFeatures.take(10).foreach{tuple =>
			println(tuple._1 + " -> " + tuple._2.mkString(","))
		}
		println("=======================================================")
		// productId -> Features
		val productFeatures: RDD[(Int, Array[Double])] = alsModel.productFeatures
		productFeatures.take(10).foreach{
			tuple => println(tuple._1 + " -> " + tuple._2.mkString(","))
		}
		
		
		// TODO: 6. 模型评估,使用RMSE评估模型,值越小,误差越小,模型越好
		// 6.1 转换测试数据集格式RDD[((userId, ProductId), rating)]
		val actualRatingsRDD: RDD[((Int, Int), Double)] = testRatings.map{tuple =>
			((tuple.user, tuple.product), tuple.rating)
		}
		// 6.2 使用模型对测试数据集预测电影评分
		val predictRatingsRDD: RDD[((Int, Int), Double)] = alsModel
			// 依据UserId和ProductId预测评分
			.predict(actualRatingsRDD.map(_._1))
			// 转换数据格式RDD[((userId, ProductId), rating)]
			.map(tuple => ((tuple.user, tuple.product), tuple.rating))
		// 6.3 合并预测值与真实值
		val predictAndActualRatingsRDD: RDD[((Int, Int), (Double, Double))] = predictRatingsRDD.join(actualRatingsRDD)
		// 6.4 模型评估,计算RMSE值
		val metrics = new RegressionMetrics(predictAndActualRatingsRDD.map(_._2))
		println(s"RMSE = ${metrics.rootMeanSquaredError}")
		
		
		// TODO 7. 推荐与预测评分
		// 7.1 预测某个用户对某个产品的评分  def predict(user: Int, product: Int): Double
		val predictRating: Double = alsModel.predict(196, 242)
		println(s"预测用户196对电影242的评分:$predictRating")
		
		println("----------------------------------------")
		// 7.2 为某个用户推荐十部电影  def recommendProducts(user: Int, num: Int): Array[Rating]
		val rmdMovies: Array[Rating] = alsModel.recommendProducts(196, 10)
		rmdMovies.foreach(println)
		
		println("----------------------------------------")
		// 7.3 为某个电影推荐10个用户  def recommendUsers(product: Int, num: Int): Array[Rating]
		val rmdUsers = alsModel.recommendUsers(242, 10)
		rmdUsers.foreach(println)
		
		// TODO: 8. 将训练得到的模型进行保存,以便后期加载使用进行推荐
		val modelPath = s"datas/als/ml-als-model-" + System.nanoTime()
		alsModel.save(sc, modelPath)
		
		// TODO: 9. 从文件系统中记载保存的模型,用于推荐预测
		val loadAlsModel: MatrixFactorizationModel = MatrixFactorizationModel
			.load(sc, modelPath)
		// 使用加载预测
		val loaPredictRating: Double = loadAlsModel.predict(196, 242)
		println(s"加载模型 -> 预测用户196对电影242的评分:$loaPredictRating")
		
		// 为了WEB UI监控,线程休眠
		Thread.sleep(10000000)
		
		// 关闭资源
		sc.stop()
	}
	
}

电影推荐模型代码思路:

(1)创建SparkConf对象,设置应用相关配置
(2)读取电影评分数据
(3)数据转换,构建RDD[Rating]
(4)调用ALS算法中显示训练函数训练模型
(5)获取模型中两个因子矩阵
(6)模型评估,使用RMSE评估模型,值越小,误差越小,模型越好
(7)推荐与预测评分
(8)将训练得到的模型进行保存,以便后期加载使用进行推荐
(9)从文件系统中记载保存的模型,用于推荐预测

使用数据计算得出以下结果:

数据源我放在这里啦:

链接:https://pan.baidu.com/s/1x4ntlxKKmEwNLam6mNPDiw?pwd=3h0i 
提取码:3h0i 

五、总结:

ALS交替最小二乘法作为一种高效的矩阵分解算法,在推荐系统中具有广泛的应用前景。通过交替优化U和V矩阵,ALS算法可以逼近原始评分矩阵,从而实现对未评分物品的预测和个性化推荐。同时,ALS算法还具有缓解冷启动问题和可扩展性等优点,使得其在大数据环境下更具优势。

  • 25
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值