基于spark的电影推荐

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/keyue123/article/details/88526431

  在《推荐系统》中,详细的介绍了常用的推荐系统,大家基本上对推荐系统有了一个认识。这里我就简单的讲述一下基于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:应用名

数据准备

  1. 导入数据
	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']
  1. 数据处理
    spark主要有四种数据类型:Vector(向量),LabeledPoint(数据点,主要用在分类回归这些算法中)、Rating(评分,用于推荐)、model(模型,训练结果)。我们这里使用的是Rating,Rating定义如下:
    R a t i n g ( u s e r , p r o d u c t , p r o d u c t ) Rating(user, product, product)

  所以我们这里只需要使用前三列: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可以分为显性训练和隐性训练
  显性训练:
A L S . t r a i n ( r a t i n g s , r a n k , i t e r a t i o n s , l a m b d a ) ALS.train(ratings, rank, iterations, lambda)
  隐性训练:
A L S . t r a i n I m p l i c i t ( r a t i n g s , r a n k , i t e r a t i o n s , l a m b d a , a l p h a ) ALS.trainImplicit(ratings, rank, iterations, lambda, alpha)
  ratings 为训练数据,格式为Rating,rank为矩阵分解时的中间数, A ( m , n ) X ( m , r a n k ) Y ( r a n k , n ) A(m, n) ≈ X(m, rank)*Y(rank, n) ,iterations 重复计算次数,默认值为5,lambda 默认值为0.01。

	model = ALS.train(movieRatings, 10, 10, 0.01)   # 模型训练

推荐

  1. 针对用户推荐
    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)]
  1. 这对电影推荐
    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

猜你喜欢

转载自blog.csdn.net/keyue123/article/details/88526431