基于spark mlllib的推荐系统学习笔记
Posted 彭宇成
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于spark mlllib的推荐系统学习笔记相关的知识,希望对你有一定的参考价值。
背景
大势所趋,几乎所有的项目都在向机器学习、深度学习靠拢:怎么在行为分析类项目中植入机器学习相关算法?目前,有两个可行的场景:智能路径与在线推荐。
- 智能路径
输入转化目标,按照转化率的高低输出一组用户的转化路径。这个功能针对大型、多业务流程的系统。 - 在线推荐
根据用户自身的属性以及点击等行为数据,在会话结束后,向用户推荐相关的产品。相对而言,在线推荐更加符合我们的业务场景
技术驱动业务,真的很费劲,再加上项目中的一些沟通问题,让人心累。一个人都跑完了马拉松,还有什么做不到:你强大的身体与心理素质足以KO一个在线推荐系统。本文旨在梳理在线推荐相关知识点,以及如何在当前项目中落地在线推荐的一些思路。
问题
在线推荐怎么落地?对于一个没有做过推荐系统的小白来说,还是老老实实一步一步学吧
分析
一、推荐系统概述
推荐系统的核心是推荐引擎,目前大致有三类推荐引擎:
A. 基于人口的统计学推荐 Demographic-based Rec
最简单的一种推荐算法,简单的根据系统用户的基本属性发现用户的相关度,然后将相似用户喜欢的其他物品推荐给当前用户:
如上图,系统发现用户A与C 比较相似,就会把A喜欢的物品推荐给C
B. 基于内容的推荐 Content-based Rec
首先按照电影的特征比如类型、导演与主演名称、时长等建模,实现分类。如上图,由于电影A与电影C 属于同一个类型的电影,对于喜欢看电影A的用户,我们就可以给他推荐类似的电影C。
上面介绍的两类推荐引擎只能对客观上相似的人/物进行互推,没法对主观上相似的人/物进行推荐-下面介绍的CFR可以做到。
C. 基于协同过滤的推荐 Collaborative Filtering-based Rec
协同过滤是在分析大量的用户行为数据基础上,推荐算法中最经典最常用的,可以为分三类:
基于用户的协同过滤(User-based CFR)
基本思路是相似的人对相似的物品感兴趣。基于用户的协同过滤与基于人口统计学的推荐机制都是计算用户的相似度,但计算方式不同:前者是基于用户的历史行为数据偏好计算用户的相似度,而后者只考虑用户本身的特征:
如上图,用户A与B相似度高,这个时候可以将用户A,B购买过的产品互推,比如把用户A购买过的旅游分期,推荐给用户B。也可以把用户B购买过的超薪贷推荐给用户A。
基于项目的协同过滤(Item-based CFR)
根据用户
根据所有用户对物品或者信息的评价,发现物品和物品之间的相似度,然后根据用户的历史偏好信息将类似的物品推荐给该用户:用户A、B在购买物品A的时候,都购买了C,可以认为物品A,C比较相似。因此给用户C推荐物品C。
- 基于模型的协同过滤(Model-based CFR)
基于模型的协同过滤推荐就是基于样本的用户喜好信息,训练一个模型,然后根据实时的用户喜好的信息进行预测推荐。常用模型有三种:
1)最近邻模型:基于距离的协同过滤算法
2)矩阵分解模型:基于矩阵分解的模型
3)图模型:社会网络图模型(Graph)
由于spark mllib中的协同过滤当前支持的是矩阵分解模型,即通过某种学习算法(常用的有ALS与 SVD)学习得到Latent Factor,因此有必要掌握LF是什么,详见 nick lee 关于Latent Factor的介绍
二、基于spark mllib的Model-base CF 推荐算法实现
这里选用python,基于jupyter notebook做实验,代码来自spark 2.2官网自带:
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("pyspark-als cf") \\
.getOrCreate()
print(spark)
输出 :
<pyspark.sql.session.SparkSession object at 0x7fcf282bfed0>
lines = spark.read.text("file:///opt/cloudera/spark2/data/mllib/als/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])))
ratings = spark.createDataFrame(ratingsRDD)
(training, test) = ratings.randomSplit([0.8, 0.2]) print(test.count())// 测试用
输出: 300
als = ALS(maxIter=5, regParam=0.01, userCol="userId", itemCol="movieId", ratingCol="rating",
coldStartStrategy="drop")
model = als.fit(training)
predictions = model.transform(test)
evaluator = RegressionEvaluator(metricName="rmse", labelCol="rating",
predictionCol="prediction")
rmse = evaluator.evaluate(predictions)
print("Root-mean-square error = " + str(rmse))
输出: Root-mean-square error = 1.67116362396
# Generate top 10 movie recommendations for each user
userRecs = model.recommendForAllUsers(10)
# Generate top 10 user recommendations for each movie
movieRecs = model.recommendForAllItems(10)
# $example off$
userRecs.show()
+------+--------------------+
|userId| recommendations|
+------+--------------------+
| 28|[[92,5.185784], [...|
| 27|[[62,3.536236], [...|
| 16|[[51,4.992403], [...|
| 3|[[83,5.032247], [...|
| 20|[[22,4.7084303], ...|
| 5|[[55,4.538338], [...|
| 15|[[46,4.8945246], ...|
| 17|[[32,6.925795], [...|
| 9|[[53,5.3842697], ...|
| 23|[[55,5.188475], [...|
| 7|[[25,4.9242287], ...|
| 21|[[29,4.9428506], ...|
| 14|[[63,5.0648594], ...|
| 0|[[62,4.9426017], ...|
| 18|[[83,5.0963383], ...|
| 26|[[51,7.0873837], ...|
| 12|[[27,5.009531], [...|
| 22|[[75,5.0503945], ...|
| 1|[[75,5.2247057], ...|
| 13|[[29,3.2354996], ...|
+------+--------------------+
only showing top 20 rows
movieRecs.show()
+-------+--------------------+
|movieId| recommendations|
+-------+--------------------+
| 31|[[12,3.7782545], ...|
| 85|[[16,4.7374864], ...|
| 65|[[23,4.781863], [...|
| 53|[[9,5.3842697], [...|
| 78|[[26,1.7019612], ...|
| 81|[[28,4.965597], [...|
| 28|[[1,3.0670986], [...|
| 27|[[12,5.009531], [...|
| 44|[[18,3.7394714], ...|
| 91|[[22,3.9710066], ...|
| 93|[[2,4.952039], [2...|
| 52|[[8,5.04642], [14...|
| 16|[[12,3.936932], [...|
| 3|[[14,2.9027457], ...|
| 20|[[17,4.8047595], ...|
| 96|[[24,4.8344407], ...|
| 5|[[16,3.139203], [...|
| 41|[[4,3.8788776], [...|
| 43|[[8,4.0396466], [...|
| 15|[[12,1.9187665], ...|
+-------+--------------------+
only showing top 20 rows
简单看一下,有5个参数:
maxIter=5, regParam=0.01, userCol="userId", itemCol="movieId", ratingCol="rating",
coldStartStrategy="drop"
这里有几个问题 :
1) maxIter、regParam以及rating参数的值怎么确定,怎么自动更新?
2) rmse 值在哪个范围内模型的效果算是可接受的?
3) rating 这个特征向量值怎么获取(喜好评价规则怎么建立)?
三、Model-Base CF 在项目中的应用
参 考: github Movie-Rec-Project-by Spark&Flask
项目解读:github 核心代码解读
on-line move rec system
四、在线推荐@魔镜的实施方案预想
折腾了这么久,现实是目前对C的产品只有薪资贷、超薪贷、毕分期与旅游贷4种,因此可以考虑分两步:
1)伪在线推荐
实时读取 kafka 中的行为数据,然后调用前期做的精准营销规则引擎,判断用户是否符合某种产品的使用情况,将符合条件的产品,在用户会话结束时,以邮件的形式,发送营销信息。
2)在线推荐
待金融产品丰富后再进行,具体实现,参考三中的项目。
参考
【1】行者小猪
【2】推荐系统的常用算法原理和实现
【3】Collaborative Filtering Spark 官网
【4】nick lee 关于Latent Factor的解答
以上是关于基于spark mlllib的推荐系统学习笔记的主要内容,如果未能解决你的问题,请参考以下文章
推荐系统系列:不到百行代码实现基于Spark的ItemCF计算