学会用Spark实现朴素贝叶斯算法

  • 这里不考虑特征的离散化处理
  • 有了上面的前提,接下来的工作就简单多了,大体分为两步,处理训练样本集和计算测试样本数据结果。

    第零步:样本数据格式

    #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次数学建模一等奖,包括全国大学生国家一等奖,在国内期刊发表过相关学术研究。两年电商数据挖掘实践,负责开发精准营销产品中的用户标签体系。发表过数据挖掘相关的多篇文章。目前在互联网金融行业从事数据挖掘工作,参与开发反欺诈实时监控系统。