Mahout Bayes分类器是按照《Tackling the Poor Assumptions of Naive Bayes Text Classiers》论文写出来了,具体查看论文

实现包括三部分:The Trainer(训练器)、The Model(模型)、The Classifier(分类器)

1、训练

首先,要对输入数据进行预处理,转化成Bayes M/R job读入数据要求的格式,即训练器输入的数据是KeyValueTextInputFormat格式,第一个字符是类标签,剩余的是特征属性(即单词)。以20个新闻的例子来说,从官网上下载的原始数据是一个分类目录,下面每个文件夹名就是类标签,里面是属于此类的一些文档(一个文件是一篇文章)。mahout通过org.apache.mahout.classifier.bayes.PrepareTwentyNewsgroups对数据进行预处理,完成的工作是对于原始的一个分类目录下面的所有文件,依次遍历,并将目录名作为类别名,就这样完成了inputDir-->outputFile的转变。如果要处理html文件的话,那么就需要在BayesFileFormatter调用html clean,extract body text的过程,生成cleaned text。

PrepareTwentyNewsgroups调用org.apache.mahout.classifier.BayesFileFormatter和org.apache.lucene.analysis.standard.StandardAnalyzer进行分析处理,将数据转换成了:类标签作为一个文件的名字,文件里每一个行(一个回车算一行)是包含在此类中的一篇文章(格式是:类标签 一篇文章中的所有单词)。

BayesFileFormatter的作用是把一个目录里的所有文件转换成一个文件,label \t content其中的文件内容全部经过tokenize,词之间加入空格,存入content。BayesFileFormatter.collapse的作用是将一个目录的所有文件加上label处理成MapReduce所需要的按行处理的文件格式,变成1个文件。

其次,调用org.apache.mahout.classifier.bayes.TrainClassifier进行训练,结果生成newsmodel。

这个类会根据命令行参数调用两个训练器:trainCNaiveBayes和trainNaiveBayes,其中trainCNaiveBayes函数调用CBayesDriver类;trainNaiveBayes调用BayesDriver类。

这里只分析org.apache.mahout.classifier.bayes.mapreduce.bayes.BayesDriver类,它实现了BayesJob接口,在runJob函数里调用4个map/reduce作业类:

第一个:BayesFeatureDriver负责Read the features in each document normalized by length of each document

第二个:BayesTfIdfDriver负责Calculate the TfIdf for each word in each label

第三个:BayesWeightSummerDriver负责alculate the Sums of weights for each label, for each feature

第四个:BayesThetaNormalizerDriver负责:Calculate the normalization factor Sigma_W_ij for each complement class

以20-news的例子分别分析这四个类:

⑴BayesFeatureDriver

所在包:package org.apache.mahout.classifier.bayes.mapreduce.common;

输入格式:KeyValueTextInputFormat.class

输出格式:BayesFeatureOutputFormat.class

输出key类型:StringTuple.class

输出value类型:DoubleWritable.class

Map:BayesFeatureMapper.class

Reduce:BayesFeatureReducer.class

注意:BayesFeatureDriver可以独立运行,默认的输入和输出:(没有试过,不知道可不可以独立运行,里面有main函数,应该是可以的,不过本人水平有限,目前不会)

input=new Path("/home/drew/mahout/bayes/20news-input");

output=new Path("/home/drew/mahout/bayes/20-news-features");

p=new BayesParameters(1) gramsize默认为1

BayesFeatureOutputFormat继承了MultipleOutputFormat,定义了产生的四个文件路径及名字,文件的格式还是SequenceFileOutputFormat.:

$OUTPUT/trainer-wordFreq

$OUTPUT/trainer-termDocCount

$OUTPUT/trainer-featureCount

$OUTPUT/trainer-docCount

①BayesFeatureMapper的输出为:

一行一个map,根据数据处理的格式即一篇文章一个map,以下的label指类标签,token是属性即单词,dKJ是某token在本篇文章中出现的次数,∑dKJ2是本篇文章中所有token出现次数的平方和,以下及后面的表格是觉得看着清楚自己画的,输出时只是里面的内容,例如:_WT,label,token空格value的值

key

value

_WT,label,token

Log[(1.0+dKJ)/(∑dKJ2)1/2]即为某词在一个文档中的TF值

通俗点就是:Log[(1.0+某属性在本篇文章中出现的次数)/(本篇文章中所有属性出现次数的平方和)1/2]

_DF,label,token

1.0

_FC,token

1.0

_LC,label

1.0

②BayesFeatureReducer的输出为:

相同的key放在一个reduce里执行合并

key

value

输出

_WT,label,token

∑Log[(1.0+dKJ)/(∑dKJ2)1/2]即某类中某属性的TF值

trainer-wordFreq

_DF,label,token

某label中出现某token的文档数

trainer-termDocCount

_FC,token

所有训练集文章中出现某token的文档数

trainer-featureCount

_LC,label

某label下的文档数

trainer-docCount

_FT,token

与_FC的value一样

没输出且只在mhaout-0.4里出现这部分计算,0.3里没有

⑵BayesTfIdfDriver

输入格式:SequenceFileInputFormat.class

输出格式:BayesTfIdfOutPutFormat.class

输出key类型:StringTuple.class

输出value类型:DoubleWritable.class

输入路径:就是第一个map/reduce生成的trainer-wordFreq、trainer-termDocCount、trainer-featureCount文件

输出:trainer-tfIdf文件

Map:BayesTfIdfMapper.class

Reduce:BayesTfIdfReducer.class

根据BayesFeatureReducer的输出文件计算TF-IDF值,但是只调用了以上的trainer-wordFreq、trainer-termDocCount、trainer-featureCount三个文件,计算完毕后会删除这些中间文件(目前还没搞懂在哪删除的,只看见bayesDriver里面有把),并生成两个文件trainer-tfIdf和trainer-vocabCount(BayesTfIdfOutPutFormat里有)。

①BayesTfIdfMapper的输出为:

TF值是调用trainer-wordFreq中的value

Idf=某类下的文档数/某类下出现该token的文档数

其中某类下出现该token的文档数是调用trainer-termDocCount中的value

key

value

_WT,label,token

TF值

_WT,label,token

logidf

_FS

1.0

②BayesTfIdfReducer的输出为:

key

value

输出

_WT,label,token

TF×logidf

trainer-tfidf

_FS

属性总数

trainer-VocabCount

⑶BayesWeightSummerDriver

输入文件格式:SequenceFileInputFormat.class

输出文件格式:BayesWeightSummerOutputFormat.class

输出key:StringTuple.class

输出value:DoubleWritable.class

输入路径:是第二个map/reduce生成的trainer-tfIdf文件

输出:trainer-weights文件

Map:BayesWeightSummerMapper.class

Reduce:BayesWeightSummerReducer.class

这里只调用了第二个map/reduce生成的trainer-tfIdf,没有调trainer-VocabCount

①BayesWeightSummerMapper的输出为:

key

value

_SJ,token

TFIdf值

_SK,label

TFIdf值

_SJSK

TFIdf值

②BayesWeightSummerReducer的输出为:

key

value

输出

_SJ,token

某属性的全部TFIdf总和

Sigma_j

_SK,label

某类下的所有属性的TFIdf总和

Sigma_k

_SJSK

所有的TFIdf值

Sigma_kSigma_j

⑷BayesThetaNormalizerDriver

输入文件格式:SequenceFileInputFormat.class

输出文件格式:SequenceFileOutputFormat.class

输出key:StringTuple.class

输出value:DoubleWritable.class

输入路径: 第二个map/reduce生成的trainer-tfIdf/下的trainer-tfIdf和trainer-VocabCount,以及trainer-weights/的Sigma_k和Sigma_kSigma_j

输出:trainer-thetaNormalizer文件

①BayesWeightSummerMapper的输出为:

Log里的分子中TFIdf是某类下某属性的TFIdf值,分母中VocabCount是属性总数

key

value

_LTN,label

Log[(TFIdf+1.0)/(sigma_k+VocabCount)]

②BayesWeightSummerReducer的输出为:

将Map的结果合并

key

value

_LTN,label

ΣLog[(TFIdf+1.0)/(sigma_k+VocabCount)]

2、模型

以上训练部分的四个job执行完毕后,整个bayes模型就建立完毕了,总共生成并保存三个目录文件:

trainer-tfIdf

trainer-weights

trainer-thetaNormalizer

我们可以将模型从分布式上Sequence文件导成本地的txt文件进行查看。

3、测试

调用类:TestClassifier

所在包:package org.apache.mahout.classifier.bayes;

根据命令行参数会选择顺序执行还是并行map/reduce执行,这里只分析并行map/reduce,执行时会调用BayesClassifierDriver类

分析BayesClassifierDriver类

先runjob,runjob中先运行BayesClassifierMapper再是BayesClassifierReducer,job执行完毕后会调用混合矩阵:ConfusionMatrix函数显示结果

⑴BayesClassifierMapper

首先,运行configure:先algorithm=new BayesAlgorithm()和datastore=new InMemoryDatastore(params),datastore时InMemoryDatastore(params)方法将模型装入到datastore中即装入Sigma_j、Sigma_k、Sigma_kSigma_j、thetaNormalizer、weight=TfIdf、alpha_i=1.0);再classifier=new classifierContext(algorithm,datastore),classifier.initialize(),即初始化classifier,初始化classifier是datastore.initialize()和algorithm.initialize(this.datastore)。

datastore的初始化:

调用SequenceFileModelReader的loadModel方法(五个Load方法):

①loadFeatureWeights(装入的是Sigma_j)生成hashmap Sigma_j{0,weight 1,weight …}其中0、1…等是属性的标号,weight是Sigma_j的value。

②loadLabelWeights(装入的是Sigma_k)生成hashmap Sigma_k{0,weight 1,weight …}其中0、1…等是label即类标签的标号,weight是Sigma_k的value。

③loadSumWeight(装入的是Sigma_kSigma_j)使datastore的成员变量Sigma_jSigma_k=value(训练得到的所有tfidf总和)。

④loadThetaNormalizer(装入的是ThetaNormalizer)生成hashmap thetaNormalizerPerlabel{0,weight 1,weight …}其中weight是传进来的value,使datastore的成员变量thetaNormalizer=Max(1.0 |weight|)。

⑤loadWeightMatrix(装入的是weight即tfidf)生成weightMatrix是SparseMatrix,其中行是属性的标号,列是label的标号,行列交叉的地方是tfidf。

algorithm的初始化:

调用datastore.getKeys,getKeys返回labeldicionary.Keys即返回一个集合,里面放的是所有的label。

其次,运行map:开始分类classifier.classifyDocument(),classifyDocument()调用algorithm.classifyDocument。先new result{unkonwm,0} categories=”label weight”即所有的label集合;再开始循环:针对每一个类进行循环,调用documenWeight:先计算文档中每个词的次数(frequency),生成一个Map叫wordlist,针对wordlist的each pair计算:∑[frequency×featureweight(datastore,label,word)]。其中featureweight共四个,都调用datastore.getWeight,以下分别分析:

①double result = 调用datastore.getWeight,稀疏矩阵的getQuick,取出矩阵的Tfidf值;

②double vocabCount =属性总数;

③double sumLableWeight =Sigma_k的值;

④double numerator =result + 1.0;

⑤double denominator = sumLableWeight + vocabCount;

⑥double weight =log(numerator/denominator)也就是=log[(Tfidf+1.0)/(Sigma_k+属性个数)];

返回的是result = -weight;

所以说,documenWeight返回的值是测试文档属于某类的概率的大小,即所有属性的在某类下的frequency×result之和与在其他类下的和值进行比较,最大值的,取出它的label,文档就属于此类。

key=_CT 正确label 分类label  value=1.0

⑵BayesClassifierReducer

只是合并map的结果。

key=_CT 正确label 分类label  value=正确分类的文档数

根据对以上∑(frequency×result)进行分析,参照贝叶斯多项式模型,frequency是对weight中取对数时转移到前面的,即log(numerator/denominator)frequency = frequency×log(numerator/denominator),weight是条件概率,即log[(numerator/denominator)frequency

×(numerator/denominator)frequency …] = ∑log(numerator/denominator)frequency因为按贝叶斯原理来说,后验概率=先验概率×条件概率,据我理解,此处为什么没有乘先验概率,可能是因为所用的20个新闻的数据每类中的文档数大致一样,先验概率几乎一样,所以没必要乘(个人猜测)。

⑶ConfusionMatrix函数显示结果

key=正确label  value={key=分类label value=值}

本文转载自:http://blog.163.com/jiayouweijiewj@126/blog/static/17123217720113115027394/

Mahout Bayes分类的更多相关文章

  1. Mahout 分类算法

    实验简介 本次课程学习了Mahout 的 Bayes 分类算法. 一.实验环境说明 1. 环境登录 无需密码自动登录,系统用户名 shiyanlou 2. 环境介绍 本实验环境采用带桌面的Ubuntu ...

  2. 机器学习 101 Mahout 简介 建立一个推荐引擎 使用 Mahout 实现集群 使用 Mahout 实现内容分类 结束语 下载资源

      机器学习 101 Mahout 简介 建立一个推荐引擎 使用 Mahout 实现集群 使用 Mahout 实现内容分类 结束语 下载资源 相关主题   在信息时代,公司和个人的成功越来越依赖于迅速 ...

  3. mahout分类

    分类看起来比聚类和推荐麻烦多了 分类算法与聚类和推荐算法的不同:必须是有明确结果的,必须是有监督的,主要用于预测和检测 Mahout的优势 mahout的分类算法对资源的要求不会快于训练数据和测试数据 ...

  4. Mahout简介

    Mahout简介 一.mahout是什么 Apache Mahout是ApacheSoftware Foundation (ASF)旗下的一个开源项目,提供了一些经典的机器学习的算法,皆在帮助开发人员 ...

  5. Apache Mahout:适合所有人的可扩展机器学习框架

    http://www.ibm.com/developerworks/cn/java/j-mahout-scaling/ 在软件的世界中,两年就像是无比漫长的时光.在过去两年中,我们看到了社交媒体的风生 ...

  6. Apache Mahout 简介 通过可伸缩、商业友好的机器学习来构建智能应用程序

    在信息时代,公司和个人的成功越来越依赖于迅速有效地将大量数据转化为可操作的信息.无论是每天处理数以千计的个人电子邮件消息,还是从海量博客文章中推测用户的意图,都需要使用一些工具来组织和增强数据. 这其 ...

  7. mahout的特性(三)

    mahout的特性 虽然在开源领域中相对较为年轻,但 Mahout 已经提供了大量功能,特别是在集群和CF 方面. Mahout 的主要特性包括: Taste CF.Taste 是 Sean Owen ...

  8. 转】Mahout分步式程序开发 聚类Kmeans

    原博文出自于: http://blog.fens.me/hadoop-mahout-kmeans/ 感谢! Mahout分步式程序开发 聚类Kmeans Hadoop家族系列文章,主要介绍Hadoop ...

  9. Mahout分步式程序开发 聚类Kmeans(转)

    Posted: Oct 14, 2013 Tags: clusterHadoopkmeansMahoutR聚类 Comments: 13 Comments Mahout分步式程序开发 聚类Kmeans ...

随机推荐

  1. Java程序员必备知识-多线程框架Executor详解

    为什么引入Executor线程池框架 new Thread()的缺点 每次new Thread()耗费性能 调用new Thread()创建的线程缺乏管理,被称为野线程,而且可以无限制创建,之间相互竞 ...

  2. 最简单的基于DirectShow的示例:视频播放器

    ===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...

  3. 给EditText的drawableRight属性的图片设置点击事件

    这个方法是通用的,不仅仅适用于EditText,也适用于TextView.AutoCompleteTextView等控件. Google官方API并没有给出一个直接的方法用来设置右边图片的点击事件,所 ...

  4. Java-IO之InputStreamReader和OutputStreamWriter

    InputStreamReader和OutputStreamWriter是字节流通向字符流的桥梁.它使用指定的差染色体读写字节并将其解码为字符.InputStreamReader的作用是将字节输入流转 ...

  5. JavaI/O体系详解

    Java中IO操作主要是指使用Java进行输入,输出操作,Java中所有的IO操作类都存放在Java.io包中,在使用时需要导入此包. 在整个Java.io包中最重要的就是5个类和一个接口.5个类指的 ...

  6. 如何在Cocos2D 1.0 中掩饰一个精灵(二)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 让我们开始吧 打开Xcode,从New Project中选择co ...

  7. 【如何快速的开发一个简单的iOS直播app】(代码篇)

    开篇([如何快速的开发一个完整的iOS直播app](原理篇)) 好久没写简书,因为好奇的我跑去学习直播了,今天就分享一下我的感慨. 目前为止直播还是比较热点的技术的,简书,git上有几篇阅读量和含金量 ...

  8. Zeroc Ice原理介绍

    Ice介绍         Ice(Internet Communications Engine)是ZeroC公司的杰作,继承了CORBA的血统,是新一代的面向对象的分布式系统中间件.Ice是RPC通 ...

  9. html倒计时代码

    <SPAN id=span_dt_dt></SPAN> <SCRIPT language=javascript> <!-- //document.write( ...

  10. android eclipse写layout文件失效问题解决

    设置 xml 文件的代码提示功能 打开 Eclipse 依次选择 Window > Preferences > Xml > Editor > Content Assist &g ...