有了上面的前提,接下来的工作就简单多了,大体分为两步,处理训练样本集和计算测试样本数据结果。
第零步:样本数据格式
#ID F1 F2 F3 F4 CF1 1 0 5 1 男2 0 1 4 0 女3 1 1 3 1 男
第一步:处理训练样本集
代码逻辑
def NBmodelformat(rdd:RDD[String],path:String)={ //定义接口:输入为读取训练样本的RDD,训练样本处理后的输出路径 val allCompute = rdd.map(_.split("\u0009")).map(record => //SEPARATOR0定义为分隔符,这里为"\u0009" { var str = "" val lengthParm = record.length for(i <- 1 until lengthParm) { if(i<lengthParm-1){ //SEPARATOR2定义为分隔符,这里为"_" val standKey = "CF"+i+"_"+record(i)+"_"+record(lengthParm-1) //对特征与类别的关联值进行计数 str=str.concat(standKey).concat("\u0009") }else{ //对分类(男/女)进行计数 val standKey = "CA"+"_"+record(lengthParm-1) str=str.concat(standKey).concat("\u0009") } } //对样本总数进行计数 str.concat("SUM").trim() } ).flatMap(_.split("\u0009")).map((_,1)).reduceByKey(_+_) //本地输出一个文件,保存到本地目录 allCompute.repartition(1).saveAsTextFile(path) }
最终得到训练样本结果如下所示:
[[email protected] model1]$ cat cidmap20161121 |more -3(CF1_1_男,1212)(CF1_0_女,205)(CF2_0_男,427)
第二步:朴素贝叶斯计算逻辑
模型demo
def NBmodels(line:String,cidMap:Map[String,Int]):String={ val record = line.split("\u0009") val manNum = cidMap.get("CA_男").getOrElse(0).toDouble val womanNum = cidMap.get("CA_女").getOrElse(0).toDouble val sum = cidMap.get("SUM").getOrElse(0).toDouble //计算先验概率,这里采取了拉普拉斯平滑处理,解决冷启动问题 val manRate = (manNum+1)/(sum+2) val womanRate = (womanNum+1)/(sum+2) var manProbability = 1.0 var womanProbability = 1.0 for(i <- 1 until record.length){ //组合key键 val womanKey = "CF"+i+"_"+record(i)+"_"+"女" val manKey = "CF"+i+"_"+record(i)+"_"+"男" val catWoman = "CA"+"_"+"女" val catMan = "CA"+"_"+"男" //确定特征向量空间的种类,解决冷启动问题 val num = 3 //获取训练模型得到的结果值 val womanValue = http://www.netofthings.cn/JieJueFangAn/2016-12/(cidMap.get(womanKey).getOrElse(0)+1)/(cidMap.get(catWoman).getOrElse(0)+num)"女" else "男" }
第三步:用测试数据集得到分类结果
驱动模块
def main(args:Array[String]):Unit={ val SAMPLEDATA = "file:///E...本地目录1" val SAMPLEMODEL = "file:///E...本地目录2" val INPUTDATA = "file:///E...本地目录3" val RESULTPATH = "file:///E...本地目录4" val sc = new SparkContext("local","TestNBModel") //删除目录文件 DealWays(sc,SAMPLEMODEL) //读取训练数据SAMPLEDATA,featureNum为特征向量个数 //首先过滤长度不标准的行 val NaiveBayesData = http://www.netofthings.cn/JieJueFangAn/2016-12/sc.textFile(SAMPLEDATA, 1).map(_.trim).filter(line =>Filter(line,6))>总结:上面主要介绍了三个步骤去编写一个简单的朴素贝叶斯算法demo,还有一些值得优化的点,写法也比较偏命令式编程(告诉计算机你想要做什么事?)。但是目的在于给一些童鞋一个印象,理解上也方便些,清楚如何去落地一个简单的算法,这很重要。
后续系列文章主要有这几个方面:
- 实现一些常用的算法模型,一切洞察背后的来龙去脉。
- 结合线上业务场景模型,介绍实际的大数据挖掘流程。
- 介绍大数据挖掘与数据产品的融合对接。
作者介绍
汪榕,3年场景建模经验,曾累计获得8次数学建模一等奖,包括全国大学生国家一等奖,在国内期刊发表过相关学术研究。两年电商数据挖掘实践,负责开发精准营销产品中的用户标签体系。发表过数据挖掘相关的多篇文章。目前在互联网金融行业从事数据挖掘工作,参与开发反欺诈实时监控系统。