整個流程包括數據處理部分和分類算法部分。數據處理部分對語料庫進行處理生成算法能執行的標準格式。分類算法部分的實現被分作三個部分:訓練器(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個新聞的數據每類中的文檔數大致一樣(先驗概率幾乎一樣)。