整个流程包括数据处理部分和分类算法部分。数据处理部分对语料库进行处理生成算法能执行的标准格式。分类算法部分的实现被分作三个部分:训练器(The Trainer)、数据模型(The Model)、分类器(The Classifier)。
数据预处理
PrepareTwentyNewsgroups
for(dir in categoryDirectorys)
BayesFileFormatter.collapse(dir,分词器,outputdir,charset,outputfile);
→ dir.listFiles(new FileProcessor())
→ FileProcessor.accept();
→ Analyzer.tokenstream();//分词,得到tokenstream
→ BayesFileFormatter.writeFile();//label\ttokens
org.apache.mahout.classifier.bayes.PrepareTwentyNewsgroups对数据进行预处理:遍历根目录(categoryDirectorys)下面的所有子目录,并将子目录名作为类别名。对于每个子目录(存放着一个类别的数据),使用listFiles遍历所有的文件,并将文件交由FileProcessor的accpet函数处理。FileProcessor使用参数提供的分词器(如,lucence)处理每个文件,得到token序列。最后,调用writeFile函数,将每个文件的数据按照“label\ttoken token ...”的格式作为一行输出到输出文件(outputDir/labelName+".txt")
分类器训练过程
大致的执行路径:
TrainClassifier.trainNaiveBayes()
BayesDriver.runJob()
→BayesFeatureDriver.runJob()
FeaturePartation//决定什么样的key的item映射到同一reducer
FeatureLabelComparator//决定了不同item到达reducer的次序
BayesFeatureMapper
BayesFeatureReducer
BayesFeatureOutput//定义了reducer的输出位置
→BayesTfIdfDriver.runJob()
BayesTfIdfMapper
BayesTfIdfReducer
→BayesWeightSummerDriver.runJob()
BayesWeightSummerMapper
BayesWeightSummerReducer
→BayesThetaNormalizerDriver.runJob() //求贝叶斯的m-估计
BayesThetaNormalizerMapper
BayesThetaNormalizerMapper
每个Job下Mapper与Reducer执行的工作与输出:
BayesFeatureMapper
一行输入就是一个文档,label为该文档的标签,token为特征即文档中的单词,BayesFeatureMapper的输出为MapReducer的标准形式:key,value。输出的每一行在数据模型里都是一个item,如下:
WEIGHT key: _WT label token value:Log[(1.0+dKJ)/(∑dKJ2)1/2] //某文档中某单词的TF值
DOCUMENT FREQUENCY key: _DF label token value: 1
FEATURE COUNT key: _FC token value: 1
FEATURE TERM FREQUENCY key: _FF token value: dkj
LABEL COUNT key: _LC label value: 1
BayesFeatureReducer
该Mapper将处理相同的key的item,并执行合并操作,并将合并的结果输出到BayesFeatureOutput类中配置的路径中。由Mapper的输出可以预见每一项输出的value的意义:
LABEL_COUNT key:_LC,label value:label下的文档数
DOCUMENT_FREQUENCY key:_DF,label,token value:label下出现token的文档数
FEATURE_COUNT key:_FC,token value:出现token的文档数
WEIGHT key:_WT,label,token value: ∑(Log[(1.0+dKJ) /SQRT(∑dKJ2)])(即label下token的TF值)
BayesTfIdfMapper
根据BayesFeatureReducer输出到文件中的数据计算IDF=某类下的文档数(LABEL_COUNT)/某类下出现该token的文档数(DOCUMENT_FREQUENCY)。输出如下:
WEIGHT key: _WT,label,token value: logidf
WEIGHT key: _WT,label,token value: tf
FEATURE_SET_SIZE key: _FS value: 1
BayesTfIdfReducer
根据Mapper输出的tf值和idf值计算TF-IDF,并统计FEATURE_SET_SIZE的总和为vocabCount,并输出:
FEATURE_SET_SIZE key: _FS value: vocabCount
WEIGHT key:_WT,label,token value: TF-IDF
BayesWeightSummerMapper
每个Mapper统计该Mapper下所有label下某token(_SJ)的TF-IDF的值总和,某label(_SK)下所有token的TF-IDF的值总和,以及所有label下所有token的TF-IDF的值:
FEATURE_SUM key: _SJ,token value: TF-IDF
LABEL_SUM key: _SK,label value: TF-IDF
TOTAL_SUM key: _SJSK value: TF-IDF
BayesWeightSummerReducer
Reducert将各个Mapper node下相同token的值合并,求得所有数据下feature、label、total值,即:
FEATURE_SUM key: _SJ,token value: SUM(TF-IDF)
LABEL_SUM key: _SK,label value: SUM(TF-IDF)
TOTAL_SUM key: _SJSK value: SUM(TF-IDF)
BayesThetaNormalizerMapper
该Mapper将求贝叶斯的m-估计,至于其必要性,以及为什么公式是这样的,详见 贝叶斯的m-估计:
LABEL_THETA_NORMALIZER key: _LTN,label value: log(( tfidf +1)/(vocabCount+SigmaK))
BayesThetaNormalizerReducer
将所有Mapper的数据执行合并操作
LABEL_THETA_NORMALIZER key: _LTN label value: SUM(log(( tfidf +1)/(vocabCount+SigmaK)))
分类器分类过程
分类过程有串行和并行两种实现,下面只介绍并行实现。
TestClassifier.classifyParallel()
BayesClassifierDriver.runJob()
→BayesClassifierMapper.configure()
ClassifierContext.initialize();
InMemoryBayesDatastore.initialize();
//将训练模型装入datastore
BayesAlgorithm.initialize();
→BayesClassifierMapper.map()
ClassifierContext.classifyDocument();
BayesAlgorithm.classifyDocument();
→BayesClassifierReducer
BayesClassifierMapper
Mapper在初始化时运行ClassifierContext.initialize(),然后调用SequenceFileModelReader的loadModel方法将输入装入datastore。其次,运行map函数,最终调用BayesAlgorithm.classifyDocument()。对每个类别循环,调用documentWeight,先计算文档中每个词的次数生成一个Map类型的wordlist,针对wordlist的each pair计算:
∑[frequency×featureweight(datastore,label,word)]。
其中featureweight函数返回log[(tfidf+1.0)/(sumLabelWeight+vocabCount)]
documenWeight返回的值是测试文档属于某类的概率的大小,即所有属性的在某类下的frequency×featureweight之和,值得注意的是sumLabelWeight是类别下权重之和。与在其他类下的和值进行比较,取出最大值的label,该文档就属于此类,并输出:
CLASSIFIER_TUPLE key:_CT correctLabel classifiedLabel value:1
BayesClassifierReducer
合并Mapper的结果,输出:
CLASSIFIER_TUPLE key:_CT correctLabel classifiedLabel value:正确分类的文档数
总结:贝叶斯原理,后验概率=先验概率×条件概率。此处没有乘先验概率,直接输出为最佳label,可能是因为所用的20个新闻的数据每类中的文档数大致一样(先验概率几乎一样)。
http://blog.csdn.net/cyningsun/article/details/8679989