协同过滤是一种根据用户对各种产品的交互与评分来推荐新产品的推荐系统技术。
协同过滤引入的地方就在于它只需要输入一系列用户/产品的交互记录;
无论是显式的交互(例如在购物网站上进行评分)还是隐式的(例如用户访问了一个
产品的页面但是没有对产品评分)交互皆可。仅仅根据这些交互,协同过滤算法就能
够知道哪些产品之间比较相似(因为相同的用户与它们发生了交互)以及哪些用户之间
比较相似,然后就可以做出新的推荐。
交替最小二乘法
MLlib/ ml中包含交替最小二乘法(ALS)的一个实现,这是一个协同过滤的常用算法,可以很好的
扩展到集群上。它位于ml.recommendation.ALS类中。
ALS会为每个用户和产品都设一个特征向量,这样用户向量与产品向量的点积就接近于它们的得分。
它接收下面所列几个参数:
rank: 使用的特征向量的大小,更大的特征向量会产生更好的模型,但是也需要话费更大的计算代价,默认10
iterations:要执行的迭代次数,默认10
lamda:正则化参数,默认0.01
alpha: 用来在ALS中计算置信度的常量,默认1.0
numUserBlocks, numProductBlocks: 切分用户和产品数据的块的数目,用来控制并行度。可以通过SparkUI观察stage计算耗时,适当调大或缩小此并行度。一般控制每个stage任务在20s内完成比较好。
implicitPrefs:显式偏好信息-false,隐式偏好信息-true,默认false(显示) 。
coldStartStrategy: 预测时冷启动策略。默认是nan, 可以选择 drop。
评分矩阵
要使用ALS算法,需要有一个由mllib.recommendation.Rating对象组成的RDD,
其中每个包含一个用户id,一个产品id和一个评分。
实现过程中的一个挑战是每个id都需要是一个32位的整数值。
如果id是字符串或者更大的数字,那么可以直接在ALS中使用id的哈希值,
即使有两个用户或者产品映射到同一个Id上,总体结果依然会不错。
还有一种办法是broadcast()一张从产品id到映射值表,来赋给每个产品一个唯一的id。
模型结果
ALS返回一个MatrixFactorizationModel对象来表示结果,
可以调用predict()来对一个由(UserId,productId)对组成的RDD进行预测评分。
也可以对使用model.recommendProducts(userId,numProducts)来为一个给定用户找到最值得推荐的前numProduct个产品。
注意,和MLlib中的其他模型不同,MatrixFactorizationModel对象很大,为每个用户和产品都存储了一个向量。
这样我们就不能把它存储到磁盘上,然后在另一个程序中读取回来。
不过,可以把模型中生成的特征向量RDD,也就是model.userFactors和model.itemFactors保存到分布式文件系统上。
最后,ALS有两个变种:显示评分(默认情况)和隐式反馈。
用于显式评分时,每个用户对于一个产品的评分需要是一个得分(例如1到5星),而预测出来的评分也是得分。
而用于隐式反馈时,每个评分代表的是用户会和给定产品发送交互的置信度(比如随着用户访问一个网页次数的增加,评分也会提高),预测出来的也是置信度。
from pyspark.ml.recommendation import ALS
ratings = spark.sql("""
select
user_id, item_id, rating
from dmb_dev.dmb_dev_als_model_rating_matrix
""").repartition(3600)
train_data, test_data = ratings.randomSplit([0.9, 0.1], seed=4226)
train_data.cache()
# 隐式数据
als = ALS() \
.setImplicitPrefs(True) \
.setAlpha(0.7) \
.setMaxIter(20) \
.setRank(10) \
.setRegParam(0.01) \
.setNumBlocks(30) \
.setUserCol("user_id") \
.setItemCol("item_id") \
.setRatingCol("rating") \
.setColdStartStrategy("drop")
print(als.explainParams())
als_model = als.fit(train_data)
als_model.write().overwrite().save(model_save_path)
# 训练集合所有用户U/ 商品I 的向量表示
als_model.userFactors.withColumnRenamed("id", "user_id")\
.write.format("orc").mode("overwrite")\
.saveAsTable("dev.dev_als_model_all_trained_users_factor_result")
als_model.itemFactors.withColumnRenamed("id", "item_id")\
.write.format("orc").mode("overwrite")\
.saveAsTable("dev.dev_als_model_all_trained_item_factor_result")