最小二乘法逻辑推导与使用代码实例(pysaprk)

一、最小二乘法来实现协同过滤的原理

假设有一个m*n的评分矩阵A,既是n个用户对m部电影评分,元素Aij既是第i个用户对第j部电影的评分。

使用最小二乘法,既是将一个稀疏的m*n评分矩阵拆分为两个秩更低的矩阵:U(m*k),V(n*k),用这两个矩阵的乘积,来近似表达这个得分矩阵;

这样做的好处是将整个矩阵的自由度m*n转成(m+n)*k;

所谓矩阵的自由度,既是矩阵中参数的个数,这样拆分了之后,既是一个降维的过程(k的极端情况,既是k=1);

上面这段话的通俗理解:比如给一个电影评分的时候,人的喜好特征是矩阵U,电影特征是矩阵V,那人的喜好矩阵和电影特征矩阵的相似度是UT*V,而相似度,既可以近似理解为得分。我们现在是逆向求解,既是我们知道的是最终的得分矩阵A,利用最小二乘法求出分解矩阵U,V;

二、重构误差

上面的原理如果理解了的话,既可以知道,最终A分解为U,V之后,原矩阵和分解矩阵之间并不是等量代换,而是由最小二乘法优化的结果,而优化的目标既是重构误差,有过神经网络或者机器学习研发经验的同学,可以把重构误差理解为损失函数。

重构误差如下:

 

这个重构误差被称为Frobenius范数,这个范数既是现在分解后的矩阵U,V和原来矩阵之间的差异程度,也即是整个模型的优化目标。

三、交替最小二乘

交替最小二乘是用来最优化这个重构误差的手段,所谓“交替”,就是指我们先随机生成然后固定它求解,再固定求解,这样交替进行下去,依次迭代。每步迭代的目的都是降低重构误差,并且误差是有下界的,所以 ALS 一定会收敛。最终会得到一个最优的重构结果。

这段话的通俗理解是:最开始已知的是A和两个随机初始化的矩阵你U,V,可以得到Frobenius范数的变量表示,我现在的目标是最小化这个损失,方法是先将V看作已知,对U求偏导,令此时偏导为0,第一次优化了U。然后U优化后,将U看作已知,对V求偏导,令偏导数为0,第一次优化了V。这样交替优化下去,既是交替最小二乘法优化。

数学推导:

推荐一篇博客,里面有精彩的理论推导:https://blog.csdn.net/lql0716/article/details/70165695

 

四、spark代码实现

from pyspark.ml.evaluation import RegressionEvaluator
from pyspark.ml.recommendation import ALS
from pyspark.sql import Row
from pyspark.sql import HiveContext
from pyspark import SparkContext, SparkConf
sc = SparkContext.getOrCreate()
spark = HiveContext(sc)
#=====================读取电影评分的数据,并进行数据预处理================================================================
lines = spark.read.text("F:\\AAAA-测试数据文件夹\\sample_movielens_ratings.txt").rdd
print(lines.collect()[:2])
parts = lines.map(lambda row: row.value.split("::"))
print(parts.collect()[:2])
ratingsRDD = parts.map(lambda p: Row(userId=int(p[0]), movieId=int(p[1]),
                                     rating=float(p[2]), timestamp=int(p[3])))
print(ratingsRDD.collect()[:2])
ratings = spark.createDataFrame(ratingsRDD)
ratings.show()
#最终预处理的格式是:Row类型,id,评分,时间戳,用户id
#Row(movieId=2, rating=3.0, timestamp=1424380312, userId=0)
#Row对象不写,就不能设置字段名,所以Row对象可以看作一个表对象
#===================数据读取、预处理 end=================================================================================

#===================将原始数据随机切分为训练集和测试集========================================================================
(training, test) = ratings.randomSplit([0.8, 0.2])
#===================数据集切分完毕 end=======================================================================================

#===================定义ALS模型=========================================================================================
# Build the recommendation model using ALS on the training data
als = ALS(maxIter=5, regParam=0.01, userCol="userId", itemCol="movieId", ratingCol="rating")
# maxIter:表示二乘法的最大迭代次数
# regParam:是Frobenius范数中正则项系数
# userCol:用户列名
# itemCol:推荐条目列名
# ratingCol:得分项列名
#==================ALS模型定义 end======================================================================================

#==================使用训练数据集和fit函数训练这个模型===================================================================
model = als.fit(training)
#==================模型训练 end=========================================================================================

#==================使用训练好的模型进行测试==============================================================================
predictions = model.transform(test)
#predictions中存储的是model对test的预测结果
evaluator = RegressionEvaluator(metricName="rmse", labelCol="rating",
                                predictionCol="prediction")
# RegressionEvaluator:是spark的机器学习库中用来对predictions的可用性(比如rmse:根均方差)进行检测的对象
rmse = evaluator.evaluate(predictions)
print("Root-mean-square error = " + str(rmse))

五、最终怎么使用训练完的模型进行预测

对一个评分矩阵A,通过最小二乘法分解为U,V之后

1、假设分解后矩阵的k为1

那要预测的话,计算对应用户特征和对应电影特征的乘积即是得分。

2、假设k为2

得分即是对应用户特征(a,b)乘以对应电影特征(c,d),即是ac+bd。

具体K是几,由优化过程决定,并不是像PCA方法一样可以认为设置,其他依次类推,总是可以预测的。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值