1)從狄利克雷分佈α中抽樣,生成文檔d的主題分佈θ
2)從主題的多項式分佈θ中抽樣,生成文檔d的第i個詞的主題zi
3)從狄利克雷分佈β中抽樣,生成主題zi對應的詞語分佈φi
4)從詞語的多項式分佈φi中採樣,最終生成詞語wi
這個模型圖的解釋如下:
1.:這個過程表示生成第n個詞對應的topic。在生成第m篇文檔的時候,先從topic骰子中抽了一個骰子,然後投擲這個骰子,得到文檔中第n個詞的topic編號
2.:這個過程表示生成文檔中的第n個詞。在手裏的K個word骰子中,選編號爲的那個骰子進行投擲,生成
這裏需要提一下狄利克雷分佈的問題:對於一個3維狄利克雷參數向量(α, α, α)來說,當α小於1時,生成的概率向量偏向於某幾維,值越小,偏得越厲害;當α大於1時,生成的概率向量傾向於中間,值越大,趨中越厲害。
經過一堆的數學推導之後,最後的形式是這個樣子的:
其中的α和β就是狄利克雷分佈的兩個參數,K是語料中的topic數,是個超參,M是語料集中的文檔數,,其中表示第k個topic產生的詞中word t的個數。
得到了p(w,z)這個乾淨的表達式之後,就可以用gibbs sampling算法對這個分佈進行採樣。爲什麼要進行採樣呢?當我們在面對一個未知或者複雜的分佈時,積分、期望或者說聯合分佈很難算出來,是個NP難問題,但是條件概率很容易算出來,這時候就要進行採樣。採樣的目的是得到這個分佈的樣本,通過這些樣本明確出該分佈的具體結構,常用MCMC來進行分佈採樣。MCMC本身解決的是無法直接採樣或理解的分佈問題的,不是對已知分佈進行採樣。gibbs是對MCMC的一種改進。在LDA中,後驗概率無法直接獲得,我們通過gibbs採樣的方法去採樣該分佈,從而得到模型結構。
我們現在需要求的是p(z|w),需要採樣的也是p(z|w)這個分佈,就是求某個單詞應該屬於什麼topic。gibbs採樣採的是(w, z),即聯合分佈的樣本。收斂後在聯合分佈的樣本空間,統計出各個參數。LDA是個生成模型,但是直接求聯合分佈概率,分母計算量比較大,只能通過gibbs採樣,採樣出聯合分佈的樣本,執行多次之後產生的樣本服從真實樣本的分佈,然後在聯合樣本空間計算出統計特性。gibbs採樣做LDA的好處是簡單,速度快,收斂結果也不錯。
以上就是整個LDA的大致過程,通俗版以及公式版。簡而言之,pLSA貝葉斯化就變成了LDA,對LDA模型進行改進有很多種方式,LDA的非參數化就變成了HDP(這個模型的優點就是自動確定topic的個數)
spark 代碼:
//屏蔽日誌
Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
val warehouseLocation = "/Java/Spark/spark-warehouse"
val spark=SparkSession
.builder()
.appName("myClusters")
.master("local[4]")
.config("spark.sql.warehouse.dir",warehouseLocation)
.getOrCreate();
val dataset_lpa=spark.read.format("libsvm")
.load("/spark-2.0.0-bin-hadoop2.6/data/mllib/sample_lda_libsvm_data.txt")
//------------------------------------1 模型訓練-----------------------------------------
/**
* k: 主題數,或者聚類中心數
* DocConcentration:文章分佈的超參數(Dirichlet分佈的參數),必需>1.0,值越大,推斷出的分佈越平滑
* TopicConcentration:主題分佈的超參數(Dirichlet分佈的參數),必需>1.0,值越大,推斷出的分佈越平滑
* MaxIterations:迭代次數,需充分迭代,至少20次以上
* setSeed:隨機種子
* CheckpointInterval:迭代計算時檢查點的間隔
* Optimizer:優化計算方法,目前支持"em", "online" ,em方法更佔內存,迭代次數多內存可能不夠會拋出stack異常
*/
val lda=new LDA()
.setK(3)
.setTopicConcentration(3)
.setDocConcentration(3)
.setOptimizer("online")
.setCheckpointInterval(10)
.setMaxIter(100)
val model=lda.fit(dataset_lpa)
/**生成的model不僅存儲了推斷的主題,還包括模型的評價方法。*/
//---------------------------------2 模型評價-------------------------------------
//模型的評價指標:ogLikelihood,logPerplexity
//(1)根據訓練集的模型分佈計算的log likelihood,越大越好。
val ll = model.logLikelihood(dataset_lpa)
//(2)Perplexity評估,越小越好
val lp = model.logPerplexity(dataset_lpa)
println(s"The lower bound on the log likelihood of the entire corpus: $ll")
println(s"The upper bound bound on perplexity: $lp")
//---------------------------------3 模型及描述------------------------------
//模型通過describeTopics、topicsMatrix來描述
//(1)描述各個主題最終的前maxTermsPerTopic個詞語(最重要的詞向量)及其權重
val topics=model.describeTopics(maxTermsPerTopic=2)
println("The topics described by their top-weighted terms:")
topics.show(false)
/**主題 主題包含最重要的詞語序號 各詞語的權重
+-----+-------------+------------------------------------------+
|topic|termIndices |termWeights |
+-----+-------------+------------------------------------------+
|0 |[5, 4, 0, 1] |[0.21169509638828377, 0.19142090510443274]|
|1 |[5, 6, 1, 2] |[0.12521929515791688, 0.10175547561034966]|
|2 |[3, 10, 6, 9]|[0.19885345685860667, 0.18794498802657686]|
+-----+-------------+------------------------------------------+
*/
//(2) topicsMatrix: 主題-詞分佈,相當於phi。
val topicsMat=model.topicsMatrix
println("topicsMatrix")
println(topicsMat.toString())
/**topicsMatrix
12.992380082908886 0.5654447550856024 16.438154549631257
10.552480038361052 0.6367807085306598 19.81281695100224
2.204054885551135 0.597153999004713 6.979803589429554
*
*/
//-----------------------------------4 對語料的主題進行聚類---------------------
val topicsProb=model.transform(dataset_lpa)
topicsProb.select("label", "topicDistribution")show(false)
/** label是文檔序號 文檔中各主題的權重
+-----+--------------------------------------------------------------+
|label|topicDistribution |
+-----+--------------------------------------------------------------+
|0.0 |[0.523730754859981,0.006564444943344147,0.46970480019667477] |
|1.0 |[0.7825074858166653,0.011001204994496623,0.206491309188838] |
|2.0 |[0.2085069748527087,0.005698459472719417,0.785794565674572] |
...
*/
spark.stop()
Dirichlet分佈的參數α、β
docConcentration(Dirichlet分佈的參數α)
topicConcentration(Dirichlet分佈的參數β)
首先要強調的是EM和Online兩種算法,上述兩個參數的設置是完全不同的。
EM方法:
(1)docConcentration: 只支持對稱先驗,K維向量的值都相同,必須>1.0。向量-1表示默認,k維向量值爲(50/k)+1。
(2)topicConcentration: 只支持對稱先驗,值必須>1.0。向量-1表示默認。
docConcentration: Only symmetric priors are supported, so all values in the provided k-dimensional vector must be identical. All values must also be >1.0. Providing Vector(-1) results in default behavior (uniform k dimensional vector with value (50/k)+1
topicConcentration: Only symmetric priors supported. Values must be >1.0. Providing -1 results in defaulting to a value of 0.1+1.
由於這些參數都有明確的設置規則,因此也就不存在調優的問題了,計算出一個固定的值就可以了