原創內容,轉載注明出處
LDA是導師10月初布置的內容,每次拿起來《LDA數學八卦》看前面的公式推導都覺得這是個很難的問題,一直拖到10月末。這周末用了兩天時間終於把LDA弄懂了,其實LDA是一個很簡單的模型,不要被前面的數學公式嚇到。當然,作為一個初學者,如果有什么理解不對的,歡迎大家批評指正。
和《LDA數學八卦》不同,我想先從這個模型說起。
現在我有M篇文章,這些文章由V個單詞組成。每個單詞可能屬於不同的主題,主題總個數是K(我們並不知道每個單詞是什么主題)。現在要根據現有的語料得出一篇新文章的主題分布,這篇文章也是由V個單詞中的某些組成的。
根據機器學習的思路,我們要先得到一個模型,通過現有的語料確定模型中的參數,然后通過模型生成新的主題分布。
這是一個非監督學習,估計模型中參數的方法是馬爾科夫鏈的平穩分布。馬爾科夫鏈的概率只和它的前一個狀態有關,不管初始狀態如何,乘上一個轉移矩陣,若干步后都會收斂到一個狀態,稱這個狀態為馬氏鏈的平穩分布。如果能讓這個分布收斂到p(x),那么當馬氏鏈收斂之后得到的轉移序列即為分布p(x)的樣本。這就是著名的MCMC。Gibbs Sampling是對MCMC方法的優化,將MCMC中的接受概率α變為1,將狀態轉移變為延坐標軸的轉移,在k維坐標軸中沿着k個坐標軸輪換采樣,收斂后得到的樣本即為p(x1,x2,...,xn)的樣本。
LDA用的就是這種Gibbs Sampling采樣方法,首先將每篇文章的主題分布和每個主題的詞匯分布設置成隨機值,按照上述方法不斷采樣,直到收斂后,每個主題的詞匯分布就可以用來生成新的文章的主題分布了!(主題的詞匯分布是公用的) 有了模型參數后,將新的文章的主題分布設置成隨機的初值,這一次主題的詞匯分布固定,按照上述方法不斷采樣,Gibbs Sampling收斂后,得到的就是新的主題分布。
以上就是LDA的全部內容!當然可能還是很迷惑,到底是如何采樣的。這就要說到Gamma函數,Beta分布,Dirichlet分布,二項分布,多項分布,以及他們的共軛分布。
生成文章中的主題分布和主題中的詞匯分布都是dirichlet分布,有了主題分布,從主題分布中取樣生成第j個詞語的主題和從詞語分布中采樣生成最終的詞語都是多項式分布。后面的是多項式分布是顯而易見的,至於前面為什么是dirchlet分布,就是因為他們倆是共軛分布。。。
知道這些有什么用呢?就是為了推導出最后參數的公式,這里就不列出推到過程了,最終參數的采樣在代碼中體現為
for (int k = 0; k < K; k++) { for (int t = 0; t < V; t++) { phi[k][t] = (nkt[k][t] + beta) / (nktSum[k] + V * beta); } } for (int m = 0; m < M; m++) { for (int k = 0; k < K; k++) { theta[m][k] = (nmk[m][k] + alpha) / (nmkSum[m] + K * alpha); } }
其中phi是主題的詞匯分布,theta是文檔的主題分布。nmk是文章m中主題為k的單詞總個數,nkt是主題k中單詞t的總個數。nmksum是文章m中所有主題單詞總個數,nktsum是主題k中所有單詞總個數。每個單詞的主題每次更新為
private int sampleTopicZ(int m, int n) { // TODO Auto-generated method stub // Sample from p(z_i|z_-i, w) using Gibbs upde rule // Remove topic label for w_{m,n} int oldTopic = z[m][n]; nmk[m][oldTopic]--; nkt[oldTopic][doc[m][n]]--; nmkSum[m]--; nktSum[oldTopic]--; // Compute p(z_i = k|z_-i, w) double[] p = new double[K]; for (int k = 0; k < K; k++) { p[k] = (nkt[k][doc[m][n]] + beta) / (nktSum[k] + V * beta)* (nmk[m][k] + alpha) / (nmkSum[m] + K * alpha); } // Sample a new topic label for w_{m, n} like roulette // Compute cumulated probability for p for (int k = 1; k < K; k++) { p[k] += p[k - 1]; } double u = Math.random() * p[K - 1]; // p[] is unnormalised int newTopic; for (newTopic = 0; newTopic < K; newTopic++) { if (u < p[newTopic]) { break; } } // Add new topic label for w_{m, n} nmk[m][newTopic]++; nkt[newTopic][doc[m][n]]++; nmkSum[m]++; nktSum[newTopic]++; return newTopic; }
最后收斂后就得到了文檔的主題分布,主題的詞匯分布,和文章中每個單詞屬於什么主題。
LDA最淺顯的應用就是信息檢索中,訓練好參數后對每個檢索的文檔計算主題分布,根據檢索內容的主題分布和已知文檔主題分布的距離返回相似的文檔。更高級的應用還在探索中。
LDA中一些具體的公式推到可以詳見參考文獻。有了整體理解后,看懂所有的推導就不成問題了!
參考文獻:《LDA數學八卦》
《Parameter estimation for text analysis》