在《推荐系统》中,详细的介绍了常用的推荐系统,大家基本上对推荐系统有了一个认识。这里我就简单的讲述一下基于spark的推荐系统。
spark有着处理速度快,容易使用,而且可以和很多数据库融合的优势,所以在大数据分析中经常使用。具体的介绍我就不在这里赘述了,有兴趣的童鞋可以去看看《Spark快速大数据分析》,这本书详细的介绍了spark的基础知识和使用方法,是我学过spark中讲解最清晰和最容易入门的书籍,下面我们就开始推荐系统的介绍了。
下面使用的是MovieLens数据集,由于是个人练习,我使用的是 1M 数据集 ml-latest-small.zip 。spark 版本为 2.4.0。
创建spark对象
import findspark
findspark.init("/opt/spark", edit_rc=True)
from pyspark import SparkContext
sc = SparkContext("local", "john-spark")
findspark 引入 pyspark 依赖,/opt/spark 为我的 spark 安装路径。
local: 本地运行
john-spark:应用名
数据准备
- 导入数据
text = sc.textFile("./data/ml-latest-small/ratings.csv")
text = text .filter(lambda x: "movieId" not in x) # 去除标题行
导入数据,我们也可以熟悉一下数据:
text.count() # 查看数据数量
text.take(5) # 查看前5条数据
数据格式为:
['1,1,4.0,964982703',
'1,3,4.0,964981247',
'1,6,4.0,964982224',
'1,47,5.0,964983815',
'1,50,5.0,964982931']
- 数据处理
spark主要有四种数据类型:Vector(向量),LabeledPoint(数据点,主要用在分类回归这些算法中)、Rating(评分,用于推荐)、model(模型,训练结果)。我们这里使用的是Rating,Rating定义如下:
所以我们这里只需要使用前三列:userId,movieId,rating。
movieRatings = text.map(lambda x: x.split(",")[:3]) # 取出前三列
movieRatings.take(5)
不熟悉命令的可以查看《spark快速大数据分析》第四章:RDD 编程。取出来的结果如下所示:
[['1', '1', '4.0'],
['1', '3', '4.0'],
['1', '6', '4.0'],
['1', '47', '5.0'],
['1', '50', '5.0']]
根据前三列的userID, movieID, rate,我们可以获得电影的一些信息
movieRatings.map(lambda x: x[0]).distinct().count() # 用户数量
movieRatings.map(lambda x: x[1]).distinct().count() # 电影数量
可轻松分别获得在这个数据集中有用户610个,电影9724部。
模型训练
有了数据之后,我们就可以开始训练推荐的模型,在 spark 的机器学习库 MLlib 中有直接训练推荐模型的库,具体可以参考 pyspark 的官方API,我们这里主要使用的是 ALS 模块,导入方式为:
from pyspark.mllib.recommendation import ALS
我们将使用ALS.train训练,ALS.train可以分为显性训练和隐性训练
显性训练:
隐性训练:
ratings 为训练数据,格式为Rating,rank为矩阵分解时的中间数,
,iterations 重复计算次数,默认值为5,lambda 默认值为0.01。
model = ALS.train(movieRatings, 10, 10, 0.01) # 模型训练
推荐
- 针对用户推荐
ALS针对用户,可以使用model.recommendProducts(user: int, num: int) ,其中user为用户ID,num 为推荐数量。
model.recommendProducts(1, 5) # 为用户 1 推荐 5 部电影
推荐结果:
[Rating(user=1, product=3036, rating=6.581469154740313),
Rating(user=1, product=52885, rating=6.231709580290815),
Rating(user=1, product=3477, rating=6.128453453362306),
Rating(user=1, product=3635, rating=6.080639765555475),
Rating(user=1, product=3836, rating=6.0476067796079995)]
- 这对电影推荐
ALS针对用户,可以使用model.recommendUsers(product: int, num: int) ,其中product为电影ID,num 为推荐数量。
model.recommendUsers(7034, 5) # 将电影 7034 推送给 5 个用户
推荐结果:
[Rating(user=433, product=7034, rating=9.687131642078953),
Rating(user=258, product=7034, rating=9.22972547340868),
Rating(user=236, product=7034, rating=9.027718039618472),
Rating(user=549, product=7034, rating=8.945649337741106),
Rating(user=197, product=7034, rating=8.85388839846953)]
电影名显示
上面推荐的都是id,我们无法知道id对应的是哪一个用户和哪一部电影,电影名存放在 movies.csv 这份文件中,我们看看数据:
movies = sc.textFile("./data/ml-latest-small/movies.csv")
movies = movies.filter(lambda x: "movieId" not in x) # 去除标题行
movies.count()
movies.take(5)
数据显示:
9743
['1,Toy Story (1995),Adventure|Animation|Children|Comedy|Fantasy',
'2,Jumanji (1995),Adventure|Children|Fantasy',
'3,Grumpier Old Men (1995),Comedy|Romance',
'4,Waiting to Exhale (1995),Comedy|Drama|Romance',
'5,Father of the Bride Part II (1995),Comedy']
数据为movieId, title, genres。我们只需要id和title组成字典就可以将它们一一对应。
movieTitle = movies.map(lambda x: x.split(",")[: 2]).collectAsMap()# 创建字典
可以看看对应的结果:
重新推荐:
recommandP = model.recommendProducts(1, 5) # 为用户推荐电影
for p in recommandP:
print("为用户", str(p[0]), "推荐电影《", movieTitle[str(p[1])], "》,推荐评分:", p[2])
print("------------------------------------------------------------------------------------------")
recommandP = model.recommendUsers(1, 5) # 为用户推荐电影
for p in recommandP:
print("为用户", str(p[0]), "推荐电影《", movieTitle[str(p[1])], "》,推荐评分:", p[2])
推荐结果:
为用户 1 推荐电影《 Stranger Than Paradise (1984) 》,推荐评分: 7.409966775717861
为用户 1 推荐电影《 Burnt by the Sun (Utomlyonnye solntsem) (1994) 》,推荐评分: 7.162750014751613
为用户 1 推荐电影《 "World's End 》,推荐评分: 7.009930175524299
为用户 1 推荐电影《 Barcelona (1994) 》,推荐评分: 6.876207011935259
为用户 1 推荐电影《 Antonia's Line (Antonia) (1995) 》,推荐评分: 6.849347899803536
------------------------------------------------------------------------------------------
为用户 99 推荐电影《 Toy Story (1995) 》,推荐评分: 5.7616037185959375
为用户 267 推荐电影《 Toy Story (1995) 》,推荐评分: 5.399197893665546
为用户 498 推荐电影《 Toy Story (1995) 》,推荐评分: 5.3928558642123905
为用户 35 推荐电影《 Toy Story (1995) 》,推荐评分: 5.3299243033839465
为用户 558 推荐电影《 Toy Story (1995) 》,推荐评分: 5.284973512896739