美文网首页
pyspark协同过滤算法(ALS)

pyspark协同过滤算法(ALS)

作者: 米斯特芳 | 来源:发表于2021-07-25 14:23 被阅读0次

ALS:Alternating Least Square,交替最小二乘法,用于推荐系统

算法原理

假设有一矩阵R,R_{ij}表示第i个用户对第j个商品的评分,现在将其分解为用户矩阵U和商品矩阵V,即R=UV^T
那么,关联U与V的,肯定是商品的隐藏属性(可以类比隐空间概念),U_{ij}表示用户i对商品属性j的喜好程度,V_{ij}表示商品i在j属性上的评分,那么U的第一行乘以V的第一行,就是第1个用户对第1个商品的评分。

算法求解过程

先固定一个U,更新V,再固定V,更新U……交替进行。由于R中有很多是空的,所以计算误差时仅对非空计算

数学推导

分显示反馈和隐式反馈2种情况,隐式反馈表示我们的原始R矩阵并不是用户对商品的评分,而是只有用户的相关行为(比如浏览次数、收藏等),只能需要通过行为去分析用户对商品的评分

显示反馈

设R为m\timesn维,U为m\timesd维,V为n\timesd维,d表示关联用户与商品的隐空间,比如,U可以看成用户对d个商品属性的评分,V可以看成商品在d个属性上的评分,则U的第一行乘以V的第一行表示,第一个用户在第一个商品上的评分

代价函数:表示UV重构矩阵与原始矩阵R的误差的均方根,加上正则项
J(U,V)=\sum_i^m \sum_j^n [(r_{ij}-u_iv_j^T)^2+\lambda (||u_i||_2^2+||v_j||_2^2)]

算法求解
固定V求解U,J对U求导,得:U^T=(V^TV+\lambda I)^{-1}V^TR^T
同理,固定U求解V:V^T=(U^TU+\lambda I)^{-1}U^TR^T

隐式反馈

假设p_{ij}表示用户u_i对商品v_j的置信度(表示用户有没有该行为,有就是1,没有是0)p_{ij}= \{\begin{aligned} 1, r_{ij}>0\\ 0, r_{ij}=0 \end{aligned}
隐式反馈r_{ij}为0,不代表用户不喜欢,可能是没看到;如果不为0,也可能是误点,所以还要引入行为的置信度c_{ij}(表示用户行为的权重)c_{ij}=1+\alpha r_{ij}
\alpha为置信度系数

代价函数J(U,V)=\sum_i^m \sum_j^n [c_{ij}(p_{ij}-u_iv_j^T)^2+\lambda (||u_i||_2^2+||v_j||_2^2)]

算法求解
固定V求解U,J对U求导,得:U^T=(V^TC_vV+\lambda I)^{-1}V^TC_vR^T
同理,固定U求解V:V^T=(U^TC_uU+\lambda I)^{-1}U^TC_uR^T

pyspark实现

from pyspark.sql import SparkSession
from pyspark.ml.evaluation import RegressionEvaluator
from pyspark.ml.recommendation import ALS
from pyspark.sql import Row

spark = SparkSession\
        .builder\
        .appName("ALSExample")\
        .getOrCreate()

lines = spark.read.text("sample_movielens_ratings.txt").rdd
parts = lines.map(lambda row: row.value.split("::"))
ratingsRDD = parts.map(lambda p: Row(userId=int(p[0]), movieId=int(p[1]),
                                         rating=float(p[2]), timestamp=long(p[3])))
import sys
if sys.version >= '3':# demo中考虑了兼容性
    long = int
ratings = spark.createDataFrame(ratingsRDD)
(training, test) = ratings.randomSplit([0.8, 0.2])# 分出训练、测试集
# rank:表示关联用户与商品的属性数量
# maxIter:最大迭代次数
# regParam:正则化参数
# coldStartStrategy:保证计算均方误差时不含nan
# implicitPrefs:False表示显示反馈,如果隐式反馈,还需要设置alpha参数
als = ALS(rank=10,maxIter=5, regParam=0.01, userCol="userId", itemCol="movieId", ratingCol="rating",
              coldStartStrategy="drop",implicitPrefs=False,)

model = als.fit(training)

predictions = model.transform(test)# 对测试集做相同转换
evaluator = RegressionEvaluator(metricName="rmse", labelCol="rating",
                                    predictionCol="prediction")# labelCol:评分列
rmse = evaluator.evaluate(predictions)# 均方根误差

userRecs = model.recommendForAllUsers(10)# 每个用户top10商品推荐
userRecs.show()

movieRecs = model.recommendForAllItems(10)# 每个商品top10用户推荐
movieRecs.show()

# 选出指定用户,为其推荐商品
users = ratings.select(als.getUserCol()).distinct().limit(3)
userSubsetRecs = model.recommendForUserSubset(users, 10)
userSubsetRecs.show()

# 也可以选出部分商品,为其推荐用户
movies = ratings.select(als.getItemCol()).distinct().limit(3)
movieSubSetRecs = model.recommendForItemSubset(movies, 10)
movieSubSetRecs.show()

相关文章

网友评论

      本文标题:pyspark协同过滤算法(ALS)

      本文链接:https://www.haomeiwen.com/subject/yvrpmltx.html