在LDA模型原理篇咱們總結了LDA主題模型的原理,這裏咱們就從應用的角度來使用scikit-learn來學習LDA主題模型。除了scikit-learn, 還有spark MLlib和gensim庫也有LDA主題模型的類庫,使用的原理基本相似,本文關注於scikit-learn中LDA主題模型的使用。html
在scikit-learn中,LDA主題模型的類在sklearn.decomposition.LatentDirichletAllocation包中,其算法實現主要基於原理篇裏講的變分推斷EM算法,而沒有使用基於Gibbs採樣的MCMC算法實現。git
而具體到變分推斷EM算法,scikit-learn除了咱們原理篇裏講到的標準的變分推斷EM算法外,還實現了另外一種在線變分推斷EM算法,它在原理篇裏的變分推斷EM算法的基礎上,爲了不文檔內容太多太大而超過內存大小,而提供了分步訓練(partial_fit函數),即一次訓練一小批樣本文檔,逐步更新模型,最終獲得全部文檔LDA模型的方法。這個改進算法咱們沒有講,具體論文在這:「Online Learning for Latent Dirichlet Allocation」 。github
下面咱們來看看sklearn.decomposition.LatentDirichletAllocation類庫的主要參數。算法
咱們來看看LatentDirichletAllocation類的主要輸入參數:dom
1) n_topics: 即咱們的隱含主題數$K$,須要調參。$K$的大小取決於咱們對主題劃分的需求,好比咱們只須要相似區分是動物,植物,仍是非生物這樣的粗粒度需求,那麼$K$值能夠取的很小,個位數便可。若是咱們的目標是相似區分不一樣的動物以及不一樣的植物,不一樣的非生物這樣的細粒度需求,則$K$值須要取的很大,好比上千上萬。此時要求咱們的訓練文檔數量要很是的多。函數
2) doc_topic_prior:即咱們的文檔主題先驗Dirichlet分佈$\theta_d$的參數$\alpha$。通常若是咱們沒有主題分佈的先驗知識,可使用默認值$1/K$。post
3) topic_word_prior:即咱們的主題詞先驗Dirichlet分佈$\beta_k$的參數$\eta$。通常若是咱們沒有主題分佈的先驗知識,可使用默認值$1/K$。學習
4) learning_method: 即LDA的求解算法。有 ‘batch’ 和 ‘online’兩種選擇。 ‘batch’即咱們在原理篇講的變分推斷EM算法,而"online"即在線變分推斷EM算法,在"batch"的基礎上引入了分步訓練,將訓練樣本分批,逐步一批批的用樣本更新主題詞分佈的算法。默認是"online"。選擇了‘online’則咱們能夠在訓練時使用partial_fit函數分佈訓練。不過在scikit-learn 0.20版本中默認算法會改回到"batch"。建議樣本量不大隻是用來學習的話用"batch"比較好,這樣能夠少不少參數要調。而樣本太多太大的話,"online"則是首先了。spa
5)learning_decay:僅僅在算法使用"online"時有意義,取值最好在(0.5, 1.0],以保證"online"算法漸進的收斂。主要控制"online"算法的學習率,默認是0.7。通常不用修改這個參數。code
6)learning_offset:僅僅在算法使用"online"時有意義,取值要大於1。用來減少前面訓練樣本批次對最終模型的影響。
7) max_iter :EM算法的最大迭代次數。
8)total_samples:僅僅在算法使用"online"時有意義, 即分步訓練時每一批文檔樣本的數量。在使用partial_fit函數時須要。
9)batch_size: 僅僅在算法使用"online"時有意義, 即每次EM算法迭代時使用的文檔樣本的數量。
10)mean_change_tol :即E步更新變分參數的閾值,全部變分參數更新小於閾值則E步結束,轉入M步。通常不用修改默認值。
11) max_doc_update_iter: 即E步更新變分參數的最大迭代次數,若是E步迭代次數達到閾值,則轉入M步。
從上面能夠看出,若是learning_method使用"batch"算法,則須要注意的參數較少,則若是使用"online",則須要注意"learning_decay", "learning_offset",「total_samples」和「batch_size」等參數。不管是"batch"仍是"online", n_topics($K$), doc_topic_prior($\alpha$), topic_word_prior($\eta$)都要注意。若是沒有先驗知識,則主要關注與主題數$K$。能夠說,主題數$K$是LDA主題模型最重要的超參數。
下面咱們給一個LDA中文主題模型的簡單實例,從分詞一直到LDA主題模型。
完整代碼參見個人github: https://github.com/ljpzzz/machinelearning/blob/master/natural-language-processing/lda.ipynb
咱們的有下面三段文檔語料,分別放在了nlp_test0.txt, nlp_test2.txt和 nlp_test4.txt:
沙瑞金讚歎易學習的胸懷,是金山的百姓有福,但是這件事對李達康的觸動很大。易學習又回憶起他們三人分開的前一晚,你們一塊兒喝酒話別,易學習被降職到道口縣當縣長,王大路下海經商,李達康連連賠禮道歉,以爲對不起你們,他最對不起的是王大路,就和易學習一塊兒給王大路湊了5萬塊錢,王大路本身東挪西撮了5萬塊,開始下海經商。沒想到後來王大路居然作得風生水起。沙瑞金以爲他們三人,在困難時期還能以沫相助,很不容易。
沙瑞金向毛婭打聽他們家在京州的別墅,毛婭笑着說,王大路事業有成以後,要給歐陽菁和她公司的股權,她們沒有要,王大路就在京州帝豪園買了三套別墅,但是李達康和易學習都不要,這些房子都在王大路的名下,歐陽菁好像去住過,毛婭不想去,她以爲房子太大很浪費,本身家住得就很踏實。
347年(永和三年)三月,桓溫兵至彭模(今四川彭山東南),留下參軍周楚、孫盛看守輜重,本身親率步兵直攻成都。同月,成漢將領李福襲擊彭模,結果被孫盛等人擊退;而桓溫三戰三勝,一直逼近成都。
首先咱們進行分詞,並把分詞結果分別存在nlp_test1.txt, nlp_test3.txt和 nlp_test5.txt:
# -*- coding: utf-8 -*- import jieba jieba.suggest_freq('沙瑞金', True) jieba.suggest_freq('易學習', True) jieba.suggest_freq('王大路', True) jieba.suggest_freq('京州', True) #第一個文檔分詞# with open('./nlp_test0.txt') as f: document = f.read() document_decode = document.decode('GBK') document_cut = jieba.cut(document_decode) #print ' '.join(jieba_cut) result = ' '.join(document_cut) result = result.encode('utf-8') with open('./nlp_test1.txt', 'w') as f2: f2.write(result) f.close() f2.close() #第二個文檔分詞# with open('./nlp_test2.txt') as f: document2 = f.read() document2_decode = document2.decode('GBK') document2_cut = jieba.cut(document2_decode) #print ' '.join(jieba_cut) result = ' '.join(document2_cut) result = result.encode('utf-8') with open('./nlp_test3.txt', 'w') as f2: f2.write(result) f.close() f2.close() #第三個文檔分詞# jieba.suggest_freq('桓溫', True) with open('./nlp_test4.txt') as f: document3 = f.read() document3_decode = document3.decode('GBK') document3_cut = jieba.cut(document3_decode) #print ' '.join(jieba_cut) result = ' '.join(document3_cut) result = result.encode('utf-8') with open('./nlp_test5.txt', 'w') as f3: f3.write(result) f.close() f3.close()
如今咱們讀入分好詞的數據到內存備用,並打印分詞結果觀察:
with open('./nlp_test1.txt') as f3: res1 = f3.read() print res1 with open('./nlp_test3.txt') as f4: res2 = f4.read() print res2 with open('./nlp_test5.txt') as f5: res3 = f5.read() print res3
打印出的分詞結果以下:
沙瑞金 讚歎 易學習 的 胸懷 , 是 金山 的 百姓 有福 , 但是 這件 事對 李達康 的 觸動 很大 。 易學習 又 回憶起 他們 三人 分開 的 前一晚 , 你們 一塊兒 喝酒 話別 , 易學習 被 降職 到 道口 縣當 縣長 , 王大路 下海經商 , 李達康 連連 賠禮道歉 , 以爲 對不起 你們 , 他 最 對不起 的 是 王大路 , 就 和 易學習 一塊兒 給 王大路 湊 了 5 萬塊 錢 , 王大路 本身 東挪西撮 了 5 萬塊 , 開始 下海經商 。 沒想到 後來 王大路 居然 作 得 風生水 起 。 沙瑞金 以爲 他們 三人 , 在 困難 時期 還 能 以沫 相助 , 很 不 容易 。
沙瑞金 向 毛婭 打聽 他們 家 在 京州 的 別墅 , 毛婭 笑 着 說 , 王大路 事業有成 以後 , 要 給 歐陽 菁 和 她 公司 的 股權 , 她們 沒有 要 , 王大路 就 在 京州 帝豪園 買 了 三套 別墅 , 但是 李達康 和 易學習 都 不要 , 這些 房子 都 在 王大路 的 名下 , 歐陽 菁 好像 去 住 過 , 毛婭 不想 去 , 她 以爲 房子 太大 很 浪費 , 本身 家住 得 就 很 踏實 。
347 年 ( 永和 三年 ) 三月 , 桓溫 兵至 彭模 ( 今 四川 彭山 東南 ) , 留下 參軍 周楚 、 孫盛 看守 輜重 , 本身 親率 步兵 直攻 成都 。 同月 , 成漢 將領 李福 襲擊 彭模 , 結果 被 孫盛 等 人 擊退 ; 而 桓溫 三 戰三勝 , 一直 逼近 成都 。
咱們接着導入停用詞表,這裏的代碼和中文文本挖掘預處理流程總結中同樣,若是你們沒有1208個的中文停用詞表,能夠到以前的這篇文章的連接裏去下載。
#從文件導入停用詞表 stpwrdpath = "stop_words.txt" stpwrd_dic = open(stpwrdpath, 'rb') stpwrd_content = stpwrd_dic.read() #將停用詞表轉換爲list stpwrdlst = stpwrd_content.splitlines() stpwrd_dic.close()
接着咱們要把詞轉化爲詞頻向量,注意因爲LDA是基於詞頻統計的,所以通常不用TF-IDF來作文檔特徵。代碼以下:
from sklearn.feature_extraction.text import CountVectorizer from sklearn.decomposition import LatentDirichletAllocation corpus = [res1,res2,res3] cntVector = CountVectorizer(stop_words=stpwrdlst) cntTf = cntVector.fit_transform(corpus) print cntTf
輸出即爲全部文檔中各個詞的詞頻向量。有了這個詞頻向量,咱們就能夠來作LDA主題模型了,因爲咱們只有三個文檔,因此選擇主題數$K$=2。代碼以下:
lda = LatentDirichletAllocation(n_topics=2, learning_offset=50., random_state=0) docres = lda.fit_transform(cntTf)
經過fit_transform函數,咱們就能夠獲得文檔的主題模型分佈在docres中。而主題詞 分佈則在lda.components_中。咱們將其打印出來:
print docres print lda.components_
文檔主題的分佈以下:
[[ 0.00950072 0.99049928] [ 0.0168786 0.9831214 ] [ 0.98429257 0.01570743]]
可見第一個和第二個文檔較大機率屬於主題2,則第三個文檔屬於主題1.
主題和詞的分佈以下:
[[ 1.32738199 1.24830645 0.90453117 0.7416939 0.78379936 0.89659305 1.26874773 1.23261029 0.82094727 0.87788498 0.94980757 1.21509469 0.64793292 0.89061203 1.00779152 0.70321998 1.04526968 1.30907884 0.81932312 0.67798129 0.93434765 1.2937011 1.170592 0.70423093 0.93400364 0.75617108 0.69258778 0.76780266 1.17923311 0.88663943 1.2244191 0.88397724 0.74734167 1.20690264 0.73649036 1.1374004 0.69576496 0.8041923 0.83229086 0.8625258 0.88495323 0.8207144 1.66806345 0.85542475 0.71686887 0.84556777 1.25124491 0.76510471 0.84978448 1.21600212 1.66496509 0.84963486 1.24645499 1.72519498 1.23308705 0.97983681 0.77222879 0.8339811 0.85949947 0.73931864 1.33412296 0.91591144 1.6722457 0.98800604 1.26042063 1.09455497 1.24696097 0.81048961 0.79308036 0.95030603 0.83259407 1.19681066 1.18562629 0.80911991 1.19239034 0.81864393 1.24837997 0.72322227 1.23471832 0.89962384 0.7307045 1.39429334 1.22255041 0.98600185 0.77407283 0.74372971 0.71807656 0.75693778 0.83817087 1.33723701 0.79249005 0.82589143 0.72502086 1.14726838 0.83487136 0.79650741 0.72292882 0.81856129] [ 0.72740212 0.73371879 1.64230568 1.5961744 1.70396534 1.04072318 0.71245387 0.77316486 1.59584637 1.15108883 1.15939659 0.76124093 1.34750239 1.21659215 1.10029347 1.20616038 1.56146506 0.80602695 2.05479544 1.18041584 1.14597993 0.76459826 0.8218473 1.2367587 1.44906497 1.19538763 1.35241035 1.21501862 0.7460776 1.61967022 0.77892814 1.14830281 1.14293716 0.74425664 1.18887759 0.79427197 1.15820484 1.26045121 1.69001421 1.17798335 1.12624327 1.12397988 0.83866079 1.2040445 1.24788376 1.63296361 0.80850841 1.19119425 1.1318814 0.80423837 0.74137153 1.21226307 0.67200183 0.78283995 0.75366187 1.5062978 1.27081319 1.2373463 2.99243195 1.21178667 0.66714016 2.17440219 0.73626368 1.60196863 0.71547934 1.94575151 0.73691176 2.02892667 1.3528508 1.0655887 1.1460755 4.17528123 0.74939365 1.23685079 0.76431961 1.17922085 0.70112531 1.14761871 0.80877956 1.12307426 1.21107782 1.64947394 0.74983027 2.03800612 1.21378076 1.21213961 1.23397206 1.16994431 1.07224768 0.75292945 1.10391419 1.26932908 1.26207274 0.70943937 1.1236972 1.24175001 1.27929042 1.19130408]]
在實際的應用中,咱們須要對$K,\alpha,\eta$進行調參。若是是"online"算法,則可能須要對"online"算法的一些參數作調整。這裏只是給出了LDA主題模型從原始文檔到實際LDA處理的過程。但願能夠幫到你們。
(歡迎轉載,轉載請註明出處。歡迎溝通交流: liujianping-ok@163.com)