• Mahout朴素贝叶斯文本分类


    Mahout朴素贝叶斯文本分类算法

         Mahout贝叶斯分类器按照官方的说法,是按照《Tackling the PoorAssumptions of Naive Bayes Text Classiers》实现的。分为三个模块:训练、测试和分类。该文档首先简要介绍朴素贝叶斯的基本原理,然后介绍MapReduce实现的思路。

    一、MapReduce 朴素贝叶斯算法实现

    (一)预处理

         在训练和分类之前都需要将小文档合并,以及分词处理。大量的小文档会让NameNode占用太多的内存空间存储元数据,另一方面在执行MapReduce时会占用太多的Map槽。

    (二)训练

          将训练数据组织成下图的结构。子文件夹的名字为类型名,子文件夹下为该类的文档。子文件夹下不能有文件夹。

          训练数据目录结构

                                                                                                                              

         该过程将训练数据生成model,生成三个目录:trainer-tfidf、trainer-weights和trainer-thetaNormalizer 。有四个Job完成该过程。抽取正则化的特征,计算TFIDF,计算权重和计算正则化因子。

    (1)特征抽取

      输入数据格式:

    clazzlable

    文档内容

     


    Map:

    对每一篇文档分词后计算该片文档中的词频(wordcount)、、。

    输出:

      (1)归一化的词频

    key:<_WT,lable,token>

    value :

      (2)词的文档频率

    Key:  <_DF,lable,token>

    Value: 1

      (3)特征数量

    Key:<_FC,lable,token>

    Value:1

      (4)TF

    Key:<"_FF”,lable,token>

    Value:wordcount

      (5)类型数

    Key:<_LC,lable>

    Value:1

    Combiner:

        在Map计算完之后value值求和。

    Reduce:

    在reduce计算主要做特征选择。过滤掉小于最小词频数和最小文档数的词。

    最终输出:

    trainer-wordFreq,存储归一化的词频。
           trainer-termDocCount,存储文档词的文档频率。

    trainer-featureCount,存储特征数量。

    trainer-docCount,存储类型数量,每个类型的文档数。

    (2)计算TFIDF

    输入:

            trainer-termDocCount,trainer-wordFreq和trainer-featureCount文件。

         将trainer-docCount添加到configuration中。

    Map:

    Configure(JobConf job){

    从configuration中加载trainer-docCount数据。

       }

       map(StringTupleDoubleWritable,StringTuple,DoubleWritable){

    1.对于TF ,直接输出。

    2.对于DF=Log(该词对应的类型的总文档数/df)。输出:Key <_WT,lable, token>   value:DF

    3.对于特征总数,特征词的数量

         输出:key <_FS> ,  value 1

    Reduce:

           1.对于特征集数量,求和,输出 key: <_FS>  value: 特征数

           2.对于TF和IDF。由于对同一个类型中的同一个词,hadoop会将其值合并在一起,这样reduce传入的同一key的迭代器中只有两个值,一个是TF值,一个是IDF值。计算tfidf =TF*IDF .

        输出:key <_WT,lable,token>  value :tfidf

    最终输出:

       trainer-tfidf 文档,key <_WT,lable,token>  value :tfidf

    (3)计算权重和

    该过程为特征和类表计算权重。

    输入:

    trainer-tfidf文件。格式为key <_WT,label ,token> ,value <tfidf>

    Map:

    1.特征和,计算全局词特征权重和

         从key中拿到token 输出其tfidf值。

        输出:key <_SJ,token>   value <tfidf>

    2.类型label和,计算全局类型权重和

    从key中拿到label,输出其tfidf。

    输出: key<_SK,label>  value <tfidf>

    3.特征及label和,计算所有特征所有类型的和

     从key中拿到tfidf,输出。

    输出: key <_SJSK>  value <tfidf>

    Reduce:

    对map的结果求和,输出。输出格式和map的一样。

    (4)计算正则化因子

    输入:

    trainer-tfidf文件。格式为key <_WT,label ,token> ,value <tfidf>

    将trainer-vocabcount 中的数据写入configuration。

    Map:

    setup(){

    从configuration中读取trainer-vocabcount数据。

    }

    Map{

       对输入的每一个词

          W=Log(tfidf/(该词的类型的特征和+总特征数))

       输出:key <_LTN,label> , value<W>

    }

    Reduce:

      对Map结果求和。

      输出:key<_LTN,label>  value <SUM(W)>

    输出:

    trainer-thetaNormalizer文件.格式Key  <_LTN,label>   value <W>

    (三)分类

    训练好模型之后,最终会生成如下图的文档结构:

                                                                                            

    首先将模型信息存储到内存中,InMemoryBayesDatastore 负责。

    分类时传入分好词的词数组document,InMemoryBayesDatastore 的实例,没有分出来时默认的类型名(默认为unknow)。

      public ClassifierResult classifyDocument(String[] document,

                                               Datastore datastore,

                                               String defaultCategory){

       maxWeight =Double.MAX_VALUE;

       ClassifierResult  clazz =new ClassifierResult ();

    For(int i  = 0 ;i <类型总数;i++){

       Label =datastore.get(i);

       Frequency=document中计算词频

       TFIDF: 该词在当前类型中的TFIDF

       Sigma_ k 该类型的tfidf和VocabCount 总特征词个数

        Weight= frequency*log[(TFIDF +1.0) /(Sigma_ k +VocabCount)]

       If(Weight<maxWeight){

          maxWeight=Weight;

          clazz.setLable(Label);

       }

    }

    clazz.setScore(maxWeight);

      return  clazz;

    }

    在map中做分类,输出分类结果。

    输入:输入文件格式:文档路径 分词后的文档内容

    Map:

    setUp(){

    加载模型。

    }

    Map(Text key,Text value){//key为文档路径  ,value为分词后的文档内容

    (1)对分词后的文档内容计算N-Gram

    (2)计算词频

    (3)类型=classifyDocument(String[] document,

                               Datastore datastore,

                              String defaultCategory)

    输出分类结果 key: 文档路径,value:类型
    }

    (四)测试

     测试本身就是分类后统计分类的正确率。

     测试数据的格式为:文档类型 分词后的文档内容

     Map:key 正确的标签,value 分词后的文档内容

        分类后的类型标签=classifyDocument();

        输出:key <_CT,正确的标签,分类后的标签>  value  1

     Reduce:对map的value求和。

    二、API

        第一部分叙述了Mahout 朴素贝叶斯分类算法的实现原理。下面叙述API的使用。在说API之前先说说文本预处理,一般来说需要训练或分类的文本都不太可能是TXT格式的,pdf、word ,html网页等等。首先要做的就是从各种格式的文件中抽取出文本。然后要将文本分词。

    (一)训练

     对于训练数据,需要组织成如图的目录结构。

                                                                                                          

    art248 ,computer200等都是类型信息,每一类中有若干文本。各类中文本的数量保持基本一致。

    每一类中都是大量的小文件,而如果需要用MapReduce做训练,需要合并小文件,组成一个或多个大文件。组合后的文件格式为:

    类型名

    分词后的一个小文件内容

    参数说明

    TrainClassfier.main(args [])

    --gramSize (-ng)

    Ngram 个数,默认为1。5以上运算量大,存储空间多,精度提高小,建议不要使用。

    --input (-i)

    训练数据路径。(注意:是HDFS路径)

    --output (-o)

    模型输出路径。(注意:是HDFS路径)

    --classifierType (-type)

    分类器类型。bayes ,默认。

    --dataSource (-source)

    模型存储位置,默认是hdfs。实际上Mahout并没有实现其它的存储方式。

    --alpha (-a)

    平滑因子,默认为1。

    --minDf (-mf)

    最小df值,默认为1。

    --minSupport (-ms)

    最小tf值,默认为1。

    训练后生成的文件:

    (二)分类

    文类数据和训练数据一样,需要抽取和分词。处理后的待分类数据存放在HDFS的一个目录下。

                                                                                                                                                    


    同样待分类数据再分之前也需要合并,原理同上。

    合并后的文件格式(SequenceFile)为:

    文件路径

    分词后的一个小文件内容

    参数说明:

    ClassifyClassifier.main(args  []);

    --defaultCat (-default)

    默认的类型,unknown。这种情况出现在模型数据为空。若分类数据出现unknown,需要检查模型。

    --testDir (-d)

    分类数据存放路径

    --encoding (-e)

    编码格式 (UTF-8)

    --gramSize (-ng)

    Ngram大小,默认为1。建议和训练的ngram值一样。

    --model (-m)

    模型路径

    --classifierType (-type)

    默认bayes.

    --dataSource (-source)

    默认hdfs

    --method (-method)

    默认MapReduce

    --verbose (-v)

    是否显示文档分类正确或者错误。注意:该参数在分类时作用不大,分类数据不知道原始的类型信息。

    --alpha (-a)

    平滑因子,默认为1。

    --outputDir (-o)

    分类后输出路径。

     















    结果文件是SequenceFile,格式如下:

    文件路径(Text)

    类型(Text)

    (三)测试

    测试数据和训练数据的组织一样,合并后的文件格式如下:

    真实类型

    分词后的文档内容

    参数说明

    TestClassifier.main(args);

    --defaultCat (-default)

    默认的类型,unknown。这种情况出现在模型数据为空。若分类数据出现unknown,需要检查模型。

    --testDir (-d)

    分类数据存放路径

    --encoding (-e)

    编码格式 (UTF-8)

    --gramSize (-ng)

    Ngram大小,默认为1。建议和训练的ngram值一样。

    --model (-m)

    模型路径

    --classifierType (-type)

    默认bayes.

    --dataSource (-source)

    默认hdfs

    --method (-method)

    默认MapReduce

    --alpha (-a)

    平滑因子

    --verbose (-v)

    是否显示分类正确或者错误。













    测试结果,模糊矩阵 

                                               

                                                    

    三、参考文档

    1.《Tackling the Poor Assumptions of Naive Bayes Text Classiers》

  • 相关阅读:
    c3p0使用
    连接池介绍
    内存角度探寻C++面向对象 之 继承、多态
    java多线程总结
    SQL关联查询总结
    java内存管理总结
    自制操作系统 (六) 分割编译与中断处理
    C++内联函数
    C++函数指针
    springmvc下实现登录验证码功能
  • 原文地址:https://www.cnblogs.com/cl1024cl/p/6205092.html
Copyright © 2020-2023  润新知