ALS:Alternating Least Square,交替最小二乘法,用于推荐系统
算法原理
假设有一矩阵R,表示第i个用户对第j个商品的评分,现在将其分解为用户矩阵U和商品矩阵V,即
那么,关联U与V的,肯定是商品的隐藏属性(可以类比隐空间概念),表示用户i对商品属性j的喜好程度,
表示商品i在j属性上的评分,那么U的第一行乘以V的第一行,就是第1个用户对第1个商品的评分。
算法求解过程
先固定一个U,更新V,再固定V,更新U……交替进行。由于R中有很多是空的,所以计算误差时仅对非空计算
数学推导
分显示反馈和隐式反馈2种情况,隐式反馈表示我们的原始R矩阵并不是用户对商品的评分,而是只有用户的相关行为(比如浏览次数、收藏等),只能需要通过行为去分析用户对商品的评分
显示反馈
设R为mn维,U为m
d维,V为n
d维,d表示关联用户与商品的隐空间,比如,U可以看成用户对d个商品属性的评分,V可以看成商品在d个属性上的评分,则U的第一行乘以V的第一行表示,第一个用户在第一个商品上的评分
代价函数:表示UV重构矩阵与原始矩阵R的误差的均方根,加上正则项
算法求解:
固定V求解U,J对U求导,得:
同理,固定U求解V:
隐式反馈
假设表示用户
对商品
的置信度(表示用户有没有该行为,有就是1,没有是0)
隐式反馈为0,不代表用户不喜欢,可能是没看到;如果不为0,也可能是误点,所以还要引入行为的置信度
(表示用户行为的权重)
为置信度系数
代价函数:
算法求解:
固定V求解U,J对U求导,得:
同理,固定U求解V:
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()
网友评论