1. 程式人生 > >利用LDA進行文字聚類(hadoop, mahout)

利用LDA進行文字聚類(hadoop, mahout)

專案原理概述

利用sqoop將資料從MySQL匯入到HDFS中,利用mahout的LDA的cvb實現對輸入資料進行聚類,並將結果更新到資料庫中。資料流向圖如下


mahout演算法分析


輸入資料格式
為<IntegerWritable, VectorWritable>的matrix矩陣,key為待聚類文字的數字編號,value為待聚類文字的單詞向量Vector, Vector的index為單詞在字典中的編號, value為TFIDF值。


演算法相關引數詳解(不包含hadoop執行引數)
專案中所有引數設定均與mahout-0.9目錄下的examples/bin/cluster-reuters.sh的147-172行設定一樣,即
$SCOUT cvb -i ${WORK_DIR}/${ROWID_MATRIX_DIR}/matrix -o ${WORK_DIR}/${LDA_DIR} -k 20 -ow -x 20 -dict ${WORK_DIR}/${DICTIONARY_FILES} -dt ${WORK_DIR}/${LDA_TOPICS_DIR} -mt ${WORK_DIR}/${LDA_MODEL_DIR}


input -- 輸入資料的hdfs路徑,這裡是/home/hadoop-user/scout_workspace/scout/dataset/reuters-out-matrix-debug/matrix
dt -- 文件主題輸出路徑,儲存了每個文件的相應topic的概率,這裡是/home/hadoop-user/scout_workspace/scout/dataset/reuters-lda-topics
mt -- model的路徑,這裡是/home/hadoop-user/scout_workspace/scout/dataset/reuters-lda-debug
k -- number of topics to learn,這裡設定成20
x -- 模型迭代次數,也就是需要多少次迭代來生成最後的Model,預設值20
seed -- Random seed,生成初始readModel時的種子,預設值System.nanoTime() % 10000
dict -- 字典路徑,這裡是/home/hadoop-user/scout_workspace/scout/dataset/reuters-out-seqdir-sparse-lda/dictionary.file-*
a -- Smoothing for document/topic distribution, document/topic分佈的平滑係數,預設為1.0E-4
e -- Smoothing for topic/term distribution, topic/term分佈的平滑係數,預設為1.0E-4
關於a和e,根據https://mahout.apache.org/users/clustering/latent-dirichlet-allocation.html描述,a和e的合適取值為k/50(k為topic數量),但是這個網頁還保留著mahout ldatopics的命令介紹,而mahout 0.8,0.9均沒有該命令,推測應該是比較陳舊的內容,因此還是根據cluster-reuters.sh中的設定來,也就是採取預設值。
mipd -- 這個引數非常重要,對於每個文件程式是先用RandomSeed來生成一個初始的readModel然後進行mipd次迭代,算出最終的model進行更新,這裡選預設值10次


LDA演算法程式分析



演算法的大致流程如下


1.解析引數與Configuration設定

2.讀取Model(第一次執行時沒有這個過程)
如果hfds上面已經有部分model,那麼程式將讀取最後一個model,並以這個model作為初始readModel來繼續進行演算法迭代,也就是說有類似於斷電-重啟的機制


3.執行演算法迭代(Mapper過程)生成LDA模型
這個過程是最為複雜的階段,許多地方我也不是很明白,我將盡最大努力進行解釋

首先分析Mapper,即CachingCVB0Mapper,顧名思義就是能夠快取的Mapper,表現在其readModel的選取上面,如果目錄裡面不存在任何model則用RandomSeed初始化一個readModel,否則讀取最近的一個model。程式將model劃分為readModel

writeModel,這兩個都是TopicModel類,並由ModelTrainer來進行排程和管理



CachingCVB0Mapper整個過程如下圖所示


在上面這個整體框架下,mahout程式應用了CVB0 Algorithm來計算LDA模型, 在map過程中通過對向量docTopic和矩陣docTopicModel的反覆迭代求解,算出每個document的docTopicModel並且在update writeModel階段將docTopicModel矩陣進行向量的相加操作,經歷完所有的map過程後得到整個corpus的docTopicModel矩陣,最終在cleanup過程中將topic的index作為key,矩陣docTopicModel作為value寫入reduce。該過程涉及到的演算法如下所示

CVB0演算法分析圖解



4.利用生成的LDA模型推匯出topic的概率分佈


演算法總結

可以看出演算法本質上面就是bayes公式和EM演算法的結合
E過程就是首先假定一個均勻分佈且歸一化的topic概率分佈向量docTopics,利用該值通過貝葉斯公式算出單詞 - 主題的概率分佈矩陣 docTopicModel(見CVB0演算法分析圖解中的第一步)


M過程就是根據生成的docTopicModel進行CVB0演算法分析圖解中的2,3,4,5步重新計算得到新的docTopics


然後反覆重複 E - M 過程n次,得到收斂後的docTopics和docTopicModel,其中docTopicModel可以用於lda模型的更新,而docTopics就是我們聚類需要的topic概率分佈向量


演算法後記
幾點問題還沒有得到解決
1.在mahout中是按照下面的式子計算docTopicModel的
double termTopicLikelihood =
   (topicTermRow.get(termIndex) + eta) * (topicWeight + alpha)/ (topicSum + eta * numTerms);
疑問就是該式子比貝葉斯公式添加了幾個平滑係數項,這樣寫的理論依據在哪裡,來源於哪篇著作或者論文,平滑係數eta和alpha分別是代表什麼含義,如何選取這兩個係數。
2.CVB0演算法分析圖解中第2步進行歸一化的理論依據,即為什麼要進行歸一化
3.update writeModel過程中對於topicTermCounts的計算
即為什麼要在每次map時候對p(topic | term)進行累加,還沒有完全想明白

專案執行環境

hadoop-1.2.1

sqoop-1.4.4

mahout-0.9

關於環境的安裝部署請參考相關文章,這裡不多加贅述。上面三個軟體在我本機的都是部署在/home/hadoop-user/mahout_workspace/目錄下。另外自己寫的scout專案部署在/home/hadoop-user/scout_workspace/目錄下

專案程式碼

專案程式碼已經放到Github上https://github.com/ehomeshasha/scout,有興趣的同學可以下載下來看下,重點檢視bin目錄下的指令碼檔案以及driver,export,analyzer等幾個包下的java檔案

整個專案架構分析
該專案的初始資料儲存在MySQL中, 演算法分析需要map/reduce過程以及hdfs檔案系統的參與, 最後將結果更新至MySQL,整個過程如圖所示


詳細流程程式碼可以用vi /home/hadoop-user/scout_workspace/scout/bin/lda/cluster-dealsaccess-lda.sh檢視,並可以用如下的圖進行表示






其中資料遷移到hdfs可採用sqoop import命令來完成,實現此過程的sh檔案在/home/hadoop-user/scout_workspace/scout/bin/sqooop_mysql_dumper.sh中,可用vi /home/hadoop-user/scout_workspace/scout/bin/sqooop_mysql_dumper.sh進行檢視。Apache Sqoop的網址連結為http://sqoop.apache.org/docs/1.4.4/SqoopUserGuide.html#_literal_sqoop_import_literal


最後一步更新MySQL可以檢視scout專案原始碼檢視詳細過程, 連線jdbc用到了Apache的DbUtils的包。DbUtils的網站連結為http://commons.apache.org/proper/commons-dbutils/


有用的指令碼檔案
scout/bin/lda/cluster-reuters-lda-debug.sh提取了mahout/examples/bin/cluster-reuters.sh的lda演算法部分並進行了步驟拆分,適用於進行演算法的除錯, scout/bin/lda/cluster-reuters-lda-debug-dumper.sh檔案是一個數據dumper指令碼檔案,可將lda演算法產生的資料dump到本地並轉換成文字格式

Scout專案架構分析

Scout的目錄結構






該scout專案的包依賴為hadoop及其依賴包, mahout-examples-0.9-job.jar, mysql-connector-java-5.1.25.jar, google的gson-2.2.4.jar包
主要職責為將資料檔案在MySQL以及HDFS之間進行轉移,程式碼量不多,花少量時間即可看懂。