基于Spark的电影推荐系统
数据文件:
u.data(userid itemid rating timestamp)
u.item(主要使用 movieid movietitle)
数据操作
把u.data导入RDD, take() x.split(‘\t’)(1)
查看userid字段的统计信息
查看udata数据矩阵的 userid列上所有值的统计信息
使用ALS.train进行训练
import org.apache.spark.mllib.recommendation.ALS
import org.apache.spark.mllib.recommendation.Rating
//读取userData前3个字段 用户,产品,评分来创建rawRatings
val userData=sc.textFile(”file:/home/hadoop/ALS/u.data”)
val rawRatings=userData.map(_.split(‘\t’).take(3))
//1.准备ALS训练数据
// import org.apache.spark.mllib.recommendation.Rating
//把3个split列case到3个名称变量中(user,movie,rating)后面便于操作
val ratingRDD= rawRatings.map{
case Array(user,movie,rating)=>Rating(user.toInt,movie.toInt,rating.toDouble)
}
//2.使用ALS.train进行训练
//使用显示Explicit rating评分训练.
// ALS.train(ratings:RDD[Rating],rank:Int,iterations:Int,lambda:Double):MatrixFactorizationModel
//隐式Implicit评分训练
// ALS.trainImplicit(ratings:RDD[Rating],rank:Int,iterations:Int,lambda:Double):MatrixFactorizationModel
//Rating(userID,productID,rating),rank 当矩阵分解matrix factorization时,将原本矩阵A(mXn)分解成X(m X rank) Y(rank X n)矩阵
//Iterator ALS算法重复计算次数,建议10~20
//lambda 建议0.01 会影响准确度|时间
//MatrixFactorizationMode训练完成后产生的模型,训练时会执行矩阵分解。模型对象成员 rank,
userFeatures:RDD[(Int,Array[Double])]分解后的用户矩阵X(m*rank)
productFeatures:RDD[(Int,Array[Double])]分解后的产品矩阵Y(m*rank)
val model=ALS.train(ratingrdd,10,10,0.01)
使用模型推荐
//1.针对用户 推荐电影
model.recommendProducts(196,5).mkString("\n")
//传入user=196被推荐用户ID,num=5 推荐数, 返回Array[Rating]
//2.针对用户 推荐产品的系统评分
model.predict(196,464) //系统对用户196推荐产品464的评分
//3.针对电影 推荐给用户
//当要促销某些电影时,可以找出可能对这些电影感兴趣的会员 使用model.recommendUsers(product:Int,num:Int):Array[Rating] 方法推荐
product要被推荐的电影ID,num推荐的记录数,返回系统针对产品推荐给用户的数组
model.recommendUser(464,5).mkString(“,”)
//把464推荐给用户471,系统评分 13.0232...
显示推荐电影名称
//1 创建电影ID-名称的对照表
val itemrdd=sc.textFile("file:/home/hadoop/ALS/u.item")
val moviet=itemrdd.map(_.split("\\|").take(2)).map(x=>(x(0),x(1))).collectAsMap
//map(x=>(x(0),x(1))).collect().toMap
//2显示对照表前5条数据
moviet.take(5).foreach(println)
//查询电影名称
scala> moviet(590)
res114: String = Hellraiser: Bloodline (1996)
//2 显示前5条推荐电影名称
model.recommendProducts(195,5).map(rating=>(rating.product,moviet(rating.product),rating.rating)).foreach(println)
Recommend项目代码
import java.io.File
import scala.io.Source
import org.apache.spark.{SparkContext,SparkConf}
import org.apache.spark.rdd._
import org.apache.spark.mllib.recommendation.{ALS,Rating,MatrixFactorizationModel}
main程序
val (ratingrdd,moviet)=PrepareData() //产生ratingrdd评分数据 与 moviet(id,title)
val model=ALS.train(ratingrdd,5,20,0.1) //训练模型
recommend(model,moviet) //推荐
//针对用户推荐电影
def RecommendMovies(model:MatrixfactorizationModel,movieTitle:Map[Int,String],inputUserID:Int)={
val RecomendMovie=model.recommendProducts(inputUserID,10)
RecomendMovie.foreach{r=>pritnln(i.toString+moviet(r.product)+r.rating); i+=1 }
}
//针对电影推荐用户
def RecommendUsers(model:MatrixfactorizationModel,movieTitle:Map[Int,String],inputMovieID:Int)={
val RecomendUser=model.recommendUsers(inputMovieID,10)
RecomendUser.foreach{r=>pritnln(i.toString+r.user+r.rating); i+=1 }
}
评估模型ALSEvaluation.main
调校model参数
model的rank,iterator,lambda这些参数设置会影响结果的准确度,运行时间。下面调校找出最佳参数组合
import java.io.File
import scala.io.Source
import org.apache.spark.{SparkContext,SparkConf}
import org.apache.spark.rdd._
import org.apache.spark.mllib.recommendation.{ALS,Rating,MatrixFactorizationModel}
import org.apache.spark.mllib.regression.LabeledPoint
def main(arg:Array[String]):Unit={
//1 准备数据阶段
val (trainData,validationData,testData)=prepareData()
trainData.persist();validationData.persist();testData.persist()
//2 trainData训练model,validationData评估模型的RMSE均方根误差
//参数设置会影响误差,需反复执行训练和评估找出最佳组合,最后返回
//bestModel模型进入下一阶段测试
val bestModel=trainValidation(trainData,validationData)
//3 使用testData在测试一次,避免出现overfitting(训练过度).如果rmse在trainData训练//和testData测试差异不大代表无过度
val testRmse=computeRMSE(bestModel,testData)
println(“使用testData测试bestModel,结果rmse=”+testRmse)
trainData.unpersist();validationData.unpersist();testData.unpersist()
}
1.准备数据-prepareData
def prepareData():(RDD[Rating],RDD[Rating],RDD[Rating])={
val Array(trainData,validationData,testData)=ratingrdd.randomSplit(Array(0.8,0.1,0.1))
return (trainData,validationData,testData)
}
2.进行训练评估-trainvalidation
def trainvalidation(trainData:RDD[Rating],validationData:RDD[Rating]):MatrixFactorizationModel={
//评估rank
evaluateParameter(trainData,validationData,”rank”,Array(5,10,15,20,50,100),Array(10),Array(0.1)
//评估iter
evaluateParameter(trainData,validationData,”numIterators”,Array(10),Array(5,10,15,20,25),Array(0.1));
//评估lambda
evaluateParameter(trainData,validationData,”lambda”,Array(10),Array(10),Array(0.05,0.1,1,5,10.0));
//所有参数找出最好组合
val bestModel=evaluateAllParameter(trainData,validationData, Array(5,10,15,20,50,100), Array(5,10,15,20,25), Array(0.05,0.1,1,5,10.0));
return (bestModel)
}
//以上3个参数有5*5*5=125个组合,对每一种参数组合评估Rmse 最好找出具有最小误差Rmse的参数组合就是最佳组合。
1.评估单个参数-evaluateParameter
那个参数具有比较低的误差,绘制图形
def evaluateParameter(trainData,validationData,p:String,ranks:Array[Int],its:Array[String],lambdas:Array[Double]):(Double,String)={
for(rank<-ranks;it<-its;lambda<-lambdas){
val rmse=trainModel(trainData,validationData,rank,it,lambda)
val pData=p match{
case “rank”=>”rank:”+rank; //pData取到for中的值
case “it”=>”it:”+it;
case “lambda”=>”lambda:”+lambda;
}
}
(rmse,pData)
}
-----------包含画图
def evaluateParameter(trainData,validationData,p:String,ranks:Array[Int],its:Array[String],lambdas:Array[Double])={
var databarchart=new DefaultCategoryDataset();
var datalinechart=new DefaultCategoryDataset();
for(rank<-ranks;it<-its;lambda<-lambdas){
val rmse=trainModel(trainData,validationData,rank,it,lambda)
val pData=p match{
case “rank”=>rank; //pData取到for中的值
case “it”=>it;
case “lambda”=>lambda;
}
databarchart.addValue(rmse,p,pData.toString)
datslinechart.addValue(time,”Time”,pData.toString)
}
Chart.plotBarLineChart(“ALS evaluations ”+p,p,”RMSE”,0.58,5,”Time”,databarchart,datalinechart);
}
def evaluateAllParameter(trainData:RDD[Rating],validationData:RDD[Rating],ranks:Array[Int],its:Array[Int],lambdas:Array[Double]):(Double,String):MatrixFactorizationModel={
val evaluations=for(rank<-ranks;it<-its;lambda<-lambdas)
yield{
val rmse=trainModel(trainData,validationData,rank,it,lambda)
(rank,it,lambda,rmse)
}
val Eval=(evaluations.sortBy(_._4))
val BestEval=Eval(0)
println(“最佳model参数 rank=”+BestEval._1+”,it=”+BestEval._2+” lambda=”+BestEval._3)
val bestModel=ALS.train(trainData,BestEval._1,BestEval._2,BestEval._3)
(bestModel)
}
2.训练模型-trainModel
def trainModel(trainData:RDD[Rating], validationData:RDD[Rating],rank:Int,it:Int,lambda:Double):Double={
val model=ALS.train(trainData,rank,it,lambda)
val rmse=computeRmse(model,validationData)
(rmse)
}
3.计算RMSE- computeRmse
root mean square error用来计算推荐系统对用户喜好的预测与实际喜好的误差平均值
误差越小代表预测值与真实值越接近
公式
def computeRmse(model:MatrixFactorizationModel,validationData:RDD[Rating]):Double={
val num= validationrdd.count
val predictedRDD=model.predict(validationrdd.map(r=>(r.user,r.product)))
//取出user+product传入预测方法,预测将结果存入predictRDD.
val predictedAndRatings=predictedRDD.map(p=>((p.user,p.product),p.rating))
.join(validationrData.map(r=>((r.user,r.product),r.rating))).values
//predictRDD预测集join ratingrdd真实集
math.sqrt(predictedAndRatings.map(x=>(x._1-x._2)*(x._1-x._2)).reduce(_+_)/num)
//针对每条数据进行计算,传入x。x._1预测结果-x._2真实数据,相乘就是平方
//reduct将全部误差求和后,在除以个数num。最后计算sqrt平方根
}
3.运行ALSEvaluation
评估rank参数 看到对RMSE没有太大差别,但是越大运行时间会增加
评估it参数 对RMSE没有太大差别,时间会增加
评估lambda参数 0.1时 RMSE最小,所需时间差异不大
所有参数交叉评估找出最好参数组合
运行evaluationAllParameter后显示
最佳model的参数组合:rank20,it15,lamdba0.1 结果rmse=0.72312434463...
最好使用testData再次验证bestModel结果0.7191119923578929,确认无overfitting问题
相同的validationData,在model中
没优化得到RMSE值0.7745372...
优化后得到RMSE值0.7134127699...
最后 找出最佳参数组合,可以修改Recommend.scala为最佳组合
val model=ALS.train(ratings,20,15,0.1)
附录:Chart
import org.jfree.chart._
import org.jfree.data.xy._
import org.jfree.data.category.DefaultCategoryDataset
import java.awt.Color
import java.awt.BasicStroke
object Chart{
def plotBarLineChart(Title:String,xLabel:String,yBarLabel:String,yBarMin:Double,yBarMax:Double,yLineLabel:String,dataBarChart:DefaultCategoryDataset,dataLineChart:DefaultCategoryDataset):Unit={
//画出Bar chart
val chart=ChartFactory.createBarChart(“”,xLabel,yBarLabel,
dataBarChart, //bar chart数据
PlotOrientation.VERTICAL, //画图方向垂直
true, //包含legend
true, //显示tooltips
false //不要url generator
)
val plot=chart.getCategoryPlot();
plot.setBackgroundPaint(new Color(0xFF,0xFF,0xFF))
plot.setDomainAxisLocation(AxisLocation.BOTTOM_OR_RIGHT)
plot.setDataset(1,dataLineChart);
plot.mapDatasetToRangeAxis(1,1)
//画柱状图 Y轴
val vn=plot.getRangeAxis();vn.setRange(yBarMin,yBarMax);vn.setAutoTickUnitSelection(true)
//画折线图y轴
val axis2=new NumberAxis(yLineLabel);plot.setRangeAxis(1,axis2);
val renderer2=new LineAndShapeRender();
renderer2.setToolTipGenerator(new StandardCategoryToolTipGenerator());
//先画柱形图,再画折线图
plot.setRenderer(1,renderer2);plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);
//创建画框
val frame=new ChartFrame(Title,chart); frame.setSize(500,500);
frame.pack();frame.setVisible(true);
}
}
基于Spark的电影推荐系统的更多相关文章
- 基于Spark的电影推荐系统(电影网站)
第一部分-电影网站: 软件架构: SpringBoot+Mybatis+JSP 项目描述:主要实现电影网站的展现 和 用户的所有动作的地方 技术选型: 技术 名称 官网 Spring Boot 容器 ...
- 基于Spark的电影推荐系统(实战简介)
写在前面 一直不知道这个专栏该如何开始写,思来想去,还是暂时把自己对这个项目的一些想法 和大家分享 的形式来展现.有什么问题,欢迎大家一起留言讨论. 这个项目的源代码是在https://github. ...
- 基于Spark的电影推荐系统(推荐系统~2)
第四部分-推荐系统-数据ETL 本模块完成数据清洗,并将清洗后的数据load到Hive数据表里面去 前置准备: spark +hive vim $SPARK_HOME/conf/hive-site.x ...
- 基于Spark的电影推荐系统(推荐系统~4)
第四部分-推荐系统-模型训练 本模块基于第3节 数据加工得到的训练集和测试集数据 做模型训练,最后得到一系列的模型,进而做 预测. 训练多个模型,取其中最好,即取RMSE(均方根误差)值最小的模型 说 ...
- 基于Spark的电影推荐系统(推荐系统~7)
基于Spark的电影推荐系统(推荐系统~7) 22/100 发布文章 liuge36 第四部分-推荐系统-实时推荐 本模块基于第4节得到的模型,开始为用户做实时推荐,推荐用户最有可能喜爱的5部电影. ...
- 基于Spark的电影推荐系统(推荐系统~1)
第四部分-推荐系统-项目介绍 行业背景: 快速:Apache Spark以内存计算为核心 通用 :一站式解决各个问题,ADHOC SQL查询,流计算,数据挖掘,图计算 完整的生态圈 只要掌握Spark ...
- 基于Mahout的电影推荐系统
基于Mahout的电影推荐系统 1.Mahout 简介 Apache Mahout 是 Apache Software Foundation(ASF) 旗下的一个开源项目,提供一些可扩展的机器学习领域 ...
- 基于pytorch的电影推荐系统
本文介绍一个基于pytorch的电影推荐系统. 代码移植自https://github.com/chengstone/movie_recommender. 原作者用了tf1.0实现了这个基于movie ...
- 基于Spark Mllib,SparkSQL的电影推荐系统
本文测试的Spark版本是1.3.1 本文将在Spark集群上搭建一个简单的小型的电影推荐系统,以为之后的完整项目做铺垫和知识积累 整个系统的工作流程描述如下: 1.某电影网站拥有可观的电影资源和用户 ...
随机推荐
- Java-Shiro(五):Shiro Realm讲解(二)IniRealm的用法、JdbcRelam的用法、自定义Realm
引入 上一篇在讲解Realm简介时,介绍过Realm包含大概4类缺省的Realm,本章主要讲解: 1)IniRealm的用法: 2)JdbcRealm基于mysql 默认表及查询语句实现认证.授权 ...
- Visual Studio下__cplusplus宏为199711L的问题
Visual Studio下__cplusplus宏为199711L的问题 / Zc:__ cplusplus(启用更新的__cplusplus宏) 该/ ZC:__ CPLUSPLUS编译器选项使_ ...
- HDU 6191 Query on A Tree ( 2017广西邀请赛 && 可持久化Trie )
题目链接 题意 : 给你一棵树.树上的每个点都有点权.之后有若干次问询.每次问询给出一个节点编号以及一个整数 X .问你以给出节点为根的子树中哪个节点和 X 异或最大.输出这个值 分析 : 看到这种树 ...
- k8s节点NotReady问题处理
我把三台虚拟机重启,发现2个节点一直处于NotReady状态,便去查找问题,到最后是因为子节点的kubelet的状态异常了,restart一下就好了,下面转一下解决的思路 昨天晚上,针对K8S环境做了 ...
- mysql bit 和 tinyint 的区别及使用场景?
bit类型语法:bit[(M)] : 位字段类型.M表示每个值的位数,范围从1到64.如果M被忽略,默认为1. tinyint是数字类型,存储小数, 一般对应编辑语言里的小字典或枚举类型. 节省空间的 ...
- JavaWeb_(SSH论坛)_六、点赞模块
基于SSH框架的小型论坛项目 一.项目入门 传送门 二.框架整合 传送门 三.用户模块 传送门 四.页面显示 传送门 五.帖子模块 传送门 六.点赞模块 传送门 七.辅助模块 传送门 联合主键 创建p ...
- Android学习_7/23
1. 在活动中使用Menu 1) 什么是Menu? 2) 怎么实现? step1:res目录下创建Menu resource file,使用<item… ...
- log4j动态配置参数
特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...
- 【python】windows更改jupyter notebook(ipython)的默认打开工作路径
写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...
- Linux搭建Samba共享服务器
实验要求: Samba文件共享服务配置与访问,配置访问用户以及相应权限. Tips:创建共享目录/test和/share,并且分别在/test下创建文件tf1(只读)tf2(读写) 在/share ...