Spark2.0機器學習系列之9: 聚類算法(LDA)

      在寫這篇文章之前,先說一些題外話。
      許多機器學習算法(如後面將要提到的LDA)涉及的數學知識太多,前前後後一大堆,理解起來不是那麼容易。
      面對複雜的機器學習模型,尤其是涉及大量數學知識的模型,我們往往要花費大量的時間和精力去推導數學算法(公式),如果過分沉湎於此會忽略了很多背後也許更重要的東西,正所謂只見樹木,不見森林,而這是缺乏遠見,是迷茫的。
      我們需要深入理解模型背後的邏輯和所蘊含的或簡或繁的思想。某些思想甚至可能是很美的思想,很偉大的思想。這些理解,使得面對複雜的問題時候,面對陌生問題時,會左右我們的選擇。我們會首先想起誰,誰是我們工具箱裏最得心應手的工具,就像自己的孩子一樣親切。而有些方法我們註定不喜歡,也用不太懂。畢竟我們不是每個人都會去寫複雜的機器學習算法code,尤其是複雜的分佈式code,但也不意味着我們不需要關注模型的數學原理,因爲沒這些數學原理的支撐,也許你永遠理解不了這個模型。但是僅僅掌握公式的推導甚至從頭到尾能寫出完整代碼,也還是遠遠不夠的。比如說我們都知道爲了控制over-fitting,需要正則化,爲什麼在看似很精確的公式裏面硬生生的多加入一個正則項,就能夠達到控制over-fitting的目的呢?又如何判斷所選擇的正則化參數是合理的?不大也不小,剛好合適。公式我們都能完整的推導吧,但也許有些事我們想的還是不那麼明白,用的時候自然也就會有一些疑慮。
      所以呢,要做到深入淺出真的很難,這也是我們學習ML需要努力的方向,理解這些ML模型背後的邏輯,所蘊含的美,所表達的的思想,甚至是哲理,也許能助你我成長到一個新的高度。

       好了,言歸正傳。在Spark2.0版本中(不是基於RDD API的MLlib),共有四種聚類方法:
     (1)K-means
     (2)Latent Dirichlet allocation (LDA)
     (3)Bisecting k-means(二分k均值算法)
     (4)Gaussian Mixture Model (GMM)。
       基於RDD API的MLLib中,共有六種聚類方法:
     (1)K-means
     (2)Gaussian mixture
     (3)Power iteration clustering (PIC)
     (4)Latent Dirichlet allocation (LDA)**
     (5)Bisecting k-means
     (6)Streaming k-means
       多了Power iteration clustering (PIC)和Streaming k-means兩種。
      本文將介紹LDA主題建模,其它方法在我的整個系列中都會有介紹。

什麼是LDA主題建模?

       隱含狄利克雷分配(LDA,Latent Dirichlet Allocation)是一種主題模型(Topic Model,即從所收集的文檔中推測主題)。 甚至可以說LDA模型現在已經成爲了主題建模中的一個標準,是實踐中最成功的主題模型之一。那麼何謂“主題”呢?,就是諸如一篇文章、一段話、一個句子所表達的中心思想。不過從統計模型的角度來說, 我們是用一個特定的詞頻分佈來刻畫主題的,並認爲一篇文章、一段話、一個句子是從一個概率模型中生成的。也就是說 在主題模型中,主題表現爲一系列相關的單詞,是這些單詞的條件概率。形象來說,主題就是一個桶,裏面裝了出現概率較高的單詞(參見下面的圖),這些單詞與這個主題有很強的相關性。

       LDA可以用來識別大規模文檔集(document collection)或語料庫(corpus)中潛藏的主題信息。它採用了詞袋(bag of words)的方法,這種方法將每一篇文檔視爲一個詞頻向量,從而將文本信息轉化爲了易於建模的數字信息。但是詞袋方法沒有考慮詞與詞之間的順序,這簡化了問題的複雜性,同時也爲模型的改進提供了契機。每一篇文檔代表了一些主題所構成的一個概率分佈,而每一個主題又代表了很多單詞所構成的一個概率分佈。
       LDA可以被認爲是如下的一個聚類過程:
       (1)各個主題(Topics)對應於各類的“質心”,每一篇文檔被視爲數據集中的一個樣本。
       (2)主題和文檔都被認爲存在一個向量空間中,這個向量空間中的每個特徵向量都是詞頻(詞袋模型)
       (3)與採用傳統聚類方法中採用距離公式來衡量不同的是,LDA使用一個基於統計模型的方程,而這個統計模型揭示出這些文檔都是怎麼產生的。

       Latent Dirichlet allocation (LDA) is a topic model which infers topics from a collection of text documents. LDA can be thought of as a clustering algorithm as follows:
       (1)Topics correspond to cluster centers, and documents correspond to examples (rows) in a dataset.
       (2)Topics and documents both exist in a feature space, where feature vectors are vectors of word counts (bag of words).
       (3)Rather than estimating a clustering using a traditional distance, LDA uses a function based on a statistical model of how text documents are generated.

       下面的幾段文字來源於:http://www.tuicool.com/articles/reaIra6

       它基於一個常識性假設:文檔集合中的所有文本均共享一定數量的隱含主題。基於該假設,它將整個文檔集特徵化爲隱含主題的集合,而每篇文本被表示爲這些隱含主題的特定比例的混合。

      LDA的這三位作者在原始論文中給了一個簡單的例子。比如給定這幾個主題:Arts、Budgets、Children、Education,在這幾個主題下,可以構造生成跟主題相關的詞語,如下圖所示:
這裏寫圖片描述

      然後可以根據這些詞語生成如下圖所示的一篇文章(其中不同顏色的詞語分別對應上圖中不同主題下的詞)
這裏寫圖片描述

      表面上理解LDA比較簡單,無非就是:當看到一篇文章後,我們往往喜歡推測這篇文章是如何生成的,我們可能會認爲某個作者先確定這篇文章的幾個主題,然後圍繞這幾個主題遣詞造句,表達成文。
      前面說了這麼多,在推導模型前,總結幾條核心思想:
      (1)隱含主題,形象的說就是一個桶,裏面裝了出現概率較高的單詞,從聚類的角度來說,各個主題(Topics)對應於各類的“質心”,主題和文檔都被認爲存在於同一個詞頻向量空間中。(2)在文檔集合中的所有文本均共享一定數量的隱含主題的假設下,我們將尋找一個基於統計模型的方程。
      LDA的核心公式如下:

p(w|d)=i=1Kp(w|zk)p(zk|d)

      d 代表某篇文檔,w 代表某個單詞,zk 代表第i主題,共有K 個主題。通俗的理解是:文檔d 以一定概率屬於主題zk ,即p(zk|d) ,而主題zk 下出現單詞w 的先驗概率是p(w|zk) ,因此在主題zk 下,文檔出現單詞w的概率是p(w|zk)p(zk|d) ,自然把文檔在所有主題下ti:K 出現單詞w 的概率加起來,就是文檔d 中出現單詞w 的概率p(w|d) (詞頻)。
      上面式子的左邊,就是文檔的詞頻,是很容易統計得到的。如果一篇文章中有很多個詞語,那麼就有很多個等式了。再如果我們收集了很多的文檔,那麼就有更多的等式了。這時候就是一個矩陣了,等式左邊的矩陣是已知的,右邊其實就是我們要求解的目標-與隱含主題相關,圖示如下:
這裏寫圖片描述
      下面來看一段很概述性的文字:
      LDA是一個層次貝葉斯模型,把模型的參數也看作隨機變量,從而可以引入控制參數的參數,實現徹底的“概率化”。LDA模型的Dirichlet的先驗分佈,文檔d上主題的多項式分佈。目前,參數估計是LDA最重要的任務,主要有兩種方法:Gibbs抽樣法(計算量大,但相對簡單和精確)和變分貝葉斯推斷法(計算量小,精度度弱)。
      看來關於LDA的數學求解,還有很多知識要學習,只好穩打穩紮,一步一步來了。大家還可以參考rickjin《LDA數學八卦》*一文。

一些數學鋪墊

參數估計(parameter estimation)

        用系統理論的語言來看:在已知系統模型結構時,用系統的輸入和輸出數據計算系統模型參數的過程。18世紀末德國數學家C.F.高斯首先提出參數估計的方法,他用最小二乘法計算天體運行的軌道。20世紀60年代,隨着電子計算機的普及,參數估計有了飛速的發展。參數估計有多種方法:矩估計、極大似然法、一致最小方差無偏估計、最小風險估計、同變估計、最小二乘法、貝葉斯估計、極大驗後法、最小風險法和極小化極大熵法等。最基本的方法是最小二乘法和極大似然法(來自百度百科,百度百科倒是經常貼“高大上”的描述方法,但是有些東西怎麼看卻都是前言不接後語,連個公式渲染都沒有,好歹簡單學學wikipedia,讓中國人上網查個數學公式賊費勁,還亂七八糟的都不標準不統一,吐槽一下,呵呵)。
        從系統理論角度出發比較“高大上”,說的也比較抽象,但是考慮到任何機器學習模型也可以理解爲一個系統,上面那段話好好理解一下也挺好,我們可以提取出下面一些理解:
        (1)參數估計並不是數理統計裏面一個特有的術語,一上來就看數理統計裏面的參數估計,就太狹隘了,也就沒有那麼深入的理解。但是也不可否認,參數估計很多方法都是數理統計的方法,但也不全是,如著名的最小二乘法(在那裏都能見到這哥們的影子)。
        (2)既然都開始估計參數了,那麼模型的結構肯定是已知的,也就是說:機器學習選取什麼算法,決策樹?還是SVM?還是Beyes概率的,深度學習的?,你自己其實已經有主意了的,手頭上有一些樣本數據(觀測值),任務是怎麼去求解(優化)系統(模型)的參數。
        正是由於最小二乘法和極大似然法也是ML裏面最基本的使用廣泛的參數估計方法,我們需要重點掌握。

       另外從數理統計學的語言講: 參數估計是根據從總體中抽取的樣本估計總體分佈中包含的未知參數的方法。人們常常需要根據手中的數據,分析或推斷數據反映的本質規律。即根據樣本數據如何選擇統計量去推斷總體的分佈或數字特徵等。統計推斷是數理統計研究的核心問題。
       可以看出:
       (1) 正是由於我們往往只能獲得一少部分樣本,卻被要求拿來估計複雜系統的真實參數,所以數學家纔會根據不同的模型,應用於不同的數據情況下,設計出如此多的巧妙辦法,儘量使估計“無偏,一致,有效”。
       (2)數理統計學裏面的參數估計目的更加明確,即推斷總體的分佈,如總體概率密度函數的類型及參數,總體樣本的統計參數(均值、方差等等)。顯然機器學習的目標更加遠大,我們需要估計各類複雜模型的參數,當然也包括一部分以概率統計理論爲基礎的ML模型(比如本文後面要介紹的GMM和LDA)。

聯合概率分佈 Joint probability distribution

       首先推薦一篇博文:zouxy09的CSDN 在裏面多個生動的例子的幫助下,比較容易看懂很多概念:
       從最大似然到EM算法淺解 http://blog.csdn.net/zouxy09/article/details/8537620/
       概率方法的很多公式都很長,看起來挺嚇人,很多時候其實都是由於採用的是聯合概率分佈,對他的形式把握透徹了,這些公式其實沒有那麼難理解。
       很多時候(比如說樸素Beyes分類器),會簡化問題,首先做獨立性假設,雖然可能並不完全滿足獨立性假設,也都這樣做,而且發現有很好的魯棒性。
       獨立性假設就是:一個事件發生概率不受其他事件影響的事件.兩(多)個獨立事件同時發生的概率等於兩(多)者分別發生的概率之積.假如AB 互相獨立,那麼AB 同時發生的概率是P(AB)=P(A)×P(B)
       如果我們抽取了N 個樣本,那麼可以認爲是發生了N 次獨立事件,所以有下面比較嚴謹的表述。
       設x1,x2,...,xN 是從概率密度函數p(x;θ) 中隨機抽取的N 個樣本,從而得到聯合概率密度函數p(X;θ) ,其中X={x1,x2,...,xN} 是樣本集。假設不同樣本之間具有統計的獨立性,則有:

p(X;θ)=p(x1,x2,...,xN;θ)=i=1Np(xi,θ)θΘ

       p(xn,θ) 代表概率密度函數的參數爲θ 時,xn 發生的概率。這裏的參數θ 是一個向量(參數向量θ=(θ1,θ2,...,θm) )。當然θ 是可以變化(不斷變化θ 代表不同的概率密度分佈函數,只是具有相同的類型),因此θ 是參數向量集合的Θ 的一個元素。
       通常寫成 p(xi;θ) ,如果寫成 p(xi|θ) 也是可以的,不過爲與條件概率 p(xi|θ) 進行區分,就寫成p(xi;θ) ,這樣可讀性更好,畢竟θ 是一個參數,而不是一個隨機變量。

最大似然法參數估計(Maximum Likehood Estimation MLE)

       最大似然法(Maximum Likelihood)這種參數估計方法:它認爲從模型總體隨機抽取n組樣本觀測值後,最合理的參數估計量應該使得從模型中抽取該n組樣本觀測值的概率最大,而不是像最小二乘估計法旨在得到使得模型能最好地擬合樣本數據的參數估計量。
       我們確實不得不佩服數學家的智慧,換個角度想問題,解決同樣一個問題的方式就完全發生了改變。但是我們也還是要看到,這兩種方法都還是有比較強的假設成份在裏面,所以數學家往往也是敢於假設的。最大似然法其實來源於一個不算太嚴謹的假設,至少我個人是這樣認爲的,但是換句話說,如果用太嚴謹的假設,統計學也就沒法玩了,所以在數理統計學面前,我們要不能太計較小概率事件,這和買彩票不一樣,再誇張一點,有時候差不多就行了,哪怕這個事情發生的概率其實還真不是太小。回到最大似然法的就是,如果我們看到了一個系統給出了有限次的結果(組成一個結果集合ObserveSet),那麼就說這個系統就具備這樣的特性——如果再做重複實驗的話,那麼產生結果集合ObserveSet的概率最大。大家看到這裏只能呵呵了。舉個極端情況的例子,大家都比較喜歡看車模美女對吧?如果某次大家去看車展,心血來潮,想調查一下本次車模都可以打多少分,也就是車模顏值是如何分佈的,所以就沒有進去,就在門口盯着看,看車展完了之後走出來的美女然後給其打分,盯了半天你終於看到一個車模走了出來,不太漂亮,甚至比較醜,頂多59分,絕對達不到及格線,於是乎,你就判斷本次車展不太行,這個系統產生的車模顏值不理想。政治老師或者語文老師一定會告訴我們犯了大錯了——以偏概全,管中窺豹,盲人摸象等等,總之是不能這麼推論。但是現實是殘酷的,有時候我們就掌握這樣不全的數據,卻要從事一項偉大的事業,所以呢,幸好我們還有統計學老師和機器學習老師,告訴我們這樣做是可以的,而且呢,如果不是這麼極端的話,多一些樣本,做出這樣的估計就不會那麼艱難,那麼糾結。比如說,你等了兩個多小時,這期間走出來20位模特,其中有12位不及格,40-59分之間,只有1位驚若天人,美得不可方物,其它的7位尚可。這時候你便可以心安理得的估計本次車展這個系統具有這樣的參數( 參展商都是一些地方小公司,模特領到的報酬比較低),導致產生的模特顏值不高,美女鳳毛麟角。我想大概齊這樣估計是可以的,不管你認不認可,反正最大似然法是這樣認爲的——本次車展系統只有很小概率產生美女。
       到現在爲止,我是大概明白了似然的意思,其實是從英文likelihood翻譯過來了,“似然似然”,似乎就是這樣吧,“最大似然”,最大可能就是這樣吧。
       有了前面聯合概率密度的基礎,需要優化的目標函數就粉墨登場了(同樣假設樣本獨立分佈,估計參數θ )。

L(θ)=L(θ1,θ2,...,θm)=L(x1,x2,...,xN;θ)=i=1Np(xi,θ)θΘ

由於xi 已知,所以需要改寫成:
L(θ)=L(θ1,θ2,...,θm)=L(θ|x1,x2,...,xN)=i=1Np(θ|xi)θΘ

      細心的朋友已經發現,函數已經定義成了L 函數了,不再是p ,說明正式由Likelihood(似然)接管,接下來思考問題的方式一定要變化,如果我們已知道概率密度函數px;θ ,我們可以模擬它會產生什麼的結果(也就是θ 已知,模擬會產生什麼未知結果xi )。在這裏恰好相反,xi 是已知的,估計未知參數θ ,所以函數的形式最終必須是這樣的——L(θ) 。最大似然的優化目標就是使得L(θ) 這個聯合概率密度達到最大值,把此時的參數θ 作爲真實θ 的估計。
      由於L(θ) 是連乘,由於對數函數ln的單調性,實際應用中是兩邊求對數,即
ln L(θ)=ln i=1Np(θ|xi)

並且爲了簡化運算,進一步定義:
l^=1kln L

最大似然函數ln L(θ) :
ln L(θ|x1,x2,,xn)=i=1Nln p(θ|xi)

最終估計的θ 值:
θˆMLE=argmaxθΘlˆ(θ|x1,x2,,xN)

      接下來我們稍加思考,不難發現,最大似然函數參數估計求解的步驟:
      (1)對l^(θ) 求偏導,令各個偏導數爲0,建立似然方程 。
      (2)對似然方程進行求解,得到的參數即爲所求估計值。

貝葉斯估計與最大後驗估計(MAP)

      上面提到的極大似然估計和貝葉斯估計分別代表了頻率派和貝葉斯派的觀點(看不懂沒關係,直接往下接着看,回頭再回味這句話更深刻)。
      頻率派認爲,參數是客觀存在的,只是未知而矣。因此,頻率派最關心極大似然函數,只要參數θˆMLE 求出來了,給定自變量xp(x|θˆMLE) 也就算出來了。
      相反的,貝葉斯派認爲參數也是隨機的,和一般隨機變量沒有本質區別,正是因爲參數不能固定,當給定一個輸入x 後,我們不能用一個確定的y 表示輸出結果,必須用一個概率的方式表達出來,所以貝葉斯學派的預測值是一個期望值。
      現在,假設θ 的先驗分佈爲g(θ) ,通過貝葉斯理論,對於θ 的後驗分佈如下:

f(θ|X)=f(X|θ)g(θ)f(X)=f(X|θ)g(θ)θΘf(X|θ)g(θ)dθ

      上面就是全貝葉斯估計,但是我們發現計算上面的後驗概率f(θ|X) ,通常是很難的,有一個積分項,難以找到典型的解析解,所以乾脆就忽略分母的這個積分項,用一種近似的辦法,就是將最大後驗估計的目標爲:
θˆMAP=argmaxθΘf(X|θ)g(θ)

      從結構上看,他和最大似然估計最大的不同在於,MAP多了一項先驗分佈,它體現了貝葉斯認爲參數也是隨機變量的觀點,在實際運算中通常通過超參數給出先驗分佈。
      怎麼去理解這其中的差別呢?這裏直接引用了
http://www.cnblogs.com/liliu/archive/2010/11/24/1886110.html 中的一個例子:

假設有五個袋子,各袋中都有無限量的餅乾(櫻桃口味或檸檬口味),已知五個袋子中兩種口味的比例分別是
    櫻桃 100%

    櫻桃 75% + 檸檬 25%

    櫻桃 50% + 檸檬 50%

    櫻桃 25% + 檸檬 75%

    檸檬 100%
如果只有如上所述條件,那問從同一個袋子中連續拿到2個檸檬餅乾,那麼這個袋子最有可能是上述五個的哪一個?
我們首先採用最大似然估計來解這個問題,即上面描述中成功的概率p(拿到檸檬)的0,25%,50%,75%,1。我們只需要評估一下這五個值哪個值使得似然函數最大即可,得到爲袋子5。這裏便是最大似然估計的結果。
上述最大似然估計有一個問題,就是沒有考慮到模型本身的概率分佈,下面我們擴展這個餅乾的問題。
假設拿到袋子1或5的機率都是0.1,拿到2或4的機率都是0.2,拿到3的機率是0.4,那同樣上述問題的答案呢?這個時候就變MAP了。根據題意的描述可知,p的取值分別爲0,25%,50%,75%,1,g的取值分別爲0.1,0.2,0.4,0.2,0.1.分別計算出MAP函數的結果爲:0,0.0125,0.125,0.28125,0.1.由上可知,通過MAP估計可得結果是從第4個袋子中取得的最高(其實這一點非常符合生活中的常識,雖然袋子5中的成功的概率是最高的,但是不一定容易拿到,所以還要綜合一下拿到的容易程度)。

      我自己再舉一個比較俗的例子吧,比如說面前有機會,可以追的姑娘有三個,但是你只能追其中一個(對吧?),第一個長得好(0.9,當做f=0.9 ),但是不好追(成功概率爲0.1,當做g=0.1 ),第二個長相中等(0.7),可能追得到機率(成功概率爲0.5),第三個長得不太好(0.5),可能追得到的機率(成功概率爲0.6),男同胞們大家會追那個?貝葉斯派應該會計算fg :0.09,0.35,0.30,追第二個吧。頻率派也許會想,反正我只能追一次,第一個吧。(以上純粹瞎掰,非邏輯嚴格的數學故事,敬請批評指正)。

      對於主題類的模型來說,

最大期望算法

      最大期望算法(Exception Maximization Algorithm,後文簡稱EM算法)是一種啓發式的迭代算法,用於實現用樣本對含有隱變量的模型的參數做極大似然估計。已知的概率模型內部存在隱含的變量,導致了不能直接用極大似然法來估計參數,EM算法就是通過迭代逼近的方式用實際的值帶入求解模型內部參數的算法。
      EM思想本身還是很複雜的,一句兩句還真的說不明白,可參考寫的另一篇博客。

Gibbs採樣

      越往下寫越感覺到爲了完全整明白LDA,是不是要把整個統計學都要研究一遍?!但是學習還得繼續。
      採樣(sampling)就是以一定的概率分佈,取一些樣本數據。爲什麼要幹這事呢?用來構造多變量概率分佈的隨機樣本,比如構造兩個或多個變量的聯合分佈,求積分,期望,之所以用採樣的方法,是因爲積分,期望或者聯合分佈很難計算出來。
      對很多貝葉斯推斷問題來說,有時候後驗分佈過於複雜,使得積分沒有顯示結果,數值方法也很難應用;有時候需要計算多重積分(比如後驗分佈是多元分佈時)。這些都會帶來計算上的很大困難。這也是在很長的時期內,貝葉斯統計得不到快速發展的一個原因。1990年代MCMC(Markov Chain Monte Carlo ,馬爾科夫鏈蒙特卡洛)計算方法引入到貝葉斯統計學之後,一舉解決了這個計算的難題。可以說,近年來貝葉斯統計的蓬勃發展,特別是在各個學科的廣泛應用和MCMC方法的使用有着極其密切的關係。
      MCMC( Markov Chain Monte Carlo):對於給定的概率分佈p(x),我們希望能有便捷的方式生成它對應的樣本。由於Markov鏈能收斂到平穩分佈【至於爲什麼請參考文獻16】, 於是一個很的漂亮想法是:如果我們能構造一個轉移矩陣爲P的馬氏鏈,使得該馬氏鏈的平穩分佈恰好是p(x), 那麼我們從任何一個初始狀態x0出發沿着馬氏鏈轉移, 得到一個轉移序列 x0,x1,x2,⋯xn,xn+1⋯,, 如果馬氏鏈在第n步已經收斂了,於是我們就得到了 π(x) 的樣本xn,xn+1⋯。

      這個絕妙的想法在1953年被 Metropolis想到了,爲了研究粒子系統的平穩性質, Metropolis考慮了物理學中常見的波爾茲曼分佈的採樣問題,首次提出了基於馬氏鏈的蒙特卡羅方法,即Metropolis算法,並在最早的計算機上編程實現。Metropolis 算法是首個普適的採樣方法,並啓發了一系列 MCMC方法,所以人們把它視爲隨機模擬技術騰飛的起點。 Metropolis的這篇論文被收錄在《統計學中的重大突破》中, Metropolis算法也被遴選爲二十世紀的十個最重要的算法之一。

LDA建模的過程

       應該說掌握了上述概率相關的知識以後,不難理解下面:LDA模型中一篇文檔生成的方式:
       (1)從狄利克雷分佈α 中取樣生成文檔i 的主題分佈θi
       (2)從主題的多項式分佈θi 中取樣生成文檔i第j個詞的主題zi,j
       (3)從狄利克雷分佈β 中取樣生成主題zi,j 的詞語分佈ϕzi,j
       (4)從詞語的多項式分佈ϕzi,j 中採樣最終生成詞語wi,j

LDA建模算法

      至此爲之,我們要去考慮,怎麼去計算這兩個矩陣,怎麼去優化的問題了。Spark採用的兩種優化算法:
      (1)EMLDAOptimizer 通過在likelihood函數上計算最大期望EM,提供較全面的結果。
      (2)OnlineLDAOptimizer 通過在小批量數據上迭代採樣實現online變分推斷,比較節省內存。在線變分預測是一種訓練LDA模型的技術,它以小批次增量式地處理數據。由於每次處理一小批數據,我們可以輕易地將其擴展應用到大數據集上。MLlib按照 Hoffman論文裏最初提出的算法實現了一種在線變分學習算法。
      LDA supports different inference algorithms via setOptimizer function. EMLDAOptimizer learns clustering using expectation-maximization on the likelihood function and yields comprehensive results, while OnlineLDAOptimizer uses iterative mini-batch sampling for online variational inference and is generally memory friendly.

Spark 代碼分析、參數設置及結果評價

       SPARK中可選參數
       (1)K:主題數量(或者說聚簇中心數量)
       (2)maxIterations:EM算法的最大迭代次數,設置足夠大的迭代次數非常重要,前期的迭代返回一些無用的(極其相似的)話題,但是繼續迭代多次後結果明顯改善。我們注意到這對EM算法尤其有效。,至少需要設置20次的迭代,50-100次是更合理的設置,取決於你的數據集。
       (3)docConcentration(Dirichlet分佈的參數α ):文檔在主題上分佈的先驗參數(超參數α )。當前必須大於1,值越大,推斷出的分佈越平滑。默認爲-1,自動設置。
       (4)topicConcentration(Dirichlet分佈的參數β ):主題在單詞上的先驗分佈參數。當前必須大於1,值越大,推斷出的分佈越平滑。默認爲-1,自動設置。
       (5)checkpointInterval:檢查點間隔。maxIterations很大的時候,檢查點可以幫助減少shuffle文件大小並且可以幫助故障恢復。
       SPARK中模型的評估
      (1)perplexity是一種信息理論的測量方法,b的perplexity值定義爲基於b的熵的能量(b可以是一個概率分佈,或者概率模型),通常用於概率模型的比較

       LDA takes in a collection of documents as vectors of word counts and the following parameters (set using the builder pattern):
       (1)k: Number of topics (i.e., cluster centers)
       (2):optimizer: Optimizer to use for learning the LDA model, either EMLDAOptimizer or OnlineLDAOptimizer
       (3)docConcentration: Dirichlet parameter for prior over documents’ distributions over topics. Larger values encourage smoother inferred distributions.
       (4)topicConcentration: Dirichlet parameter for prior over topics’ distributions over terms (words). Larger values encourage smoother inferred distributions.
       (5):maxIterations: Limit on the number of iterations. It is important to do enough iterations. In early iterations, EM often has useless topics, but those topics improve dramatically after more iterations. Using at least 20 and possibly 50-100 iterations is often reasonable, depending on your dataset.
      (6)checkpointInterval: If using checkpointing (set in the Spark configuration), this parameter specifies the frequency with which checkpoints will be created. If maxIterations is large, using checkpointing can help reduce shuffle file sizes on disk and help with failure recovery.
       All of spark.mllib’s LDA models support:
       (1)describeTopics: Returns topics as arrays of most important terms and term weights
       (2)topicsMatrix: Returns a vocabSize by k matrix where each column is a topic

詳細代碼註釋

import org.apache.spark.sql.SparkSession
import org.apache.log4j.{Level, Logger}
import org.apache.spark.ml.clustering.LDA

object myClusters {
  def main(args:Array[String]){

    //屏蔽日誌
    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]   |
        ...

    */
  }
}

       雖然推斷出K個主題,進行聚類是LDA的首要任務,但是從代碼第4部分輸出的結果(每篇文章的topicDistribution,即每篇文章在主題上的分佈)我們還是可以看出,LDA還可以有更多的用途:
       (1)特徵生成:LDA可以生成特徵(即topicDistribution向量)供其他機器學習算法使用。如前所述,LDA爲每一篇文章推斷一個主題分佈;K個主題即是K個數值特徵。這些特徵可以被用在像邏輯迴歸或者決策樹這樣的算法中用於預測任務。
       (2)降維:每篇文章在主題上的分佈提供了一個文章的簡潔總結。在這個降維了的特徵空間中進行文章比較,比在原始的詞彙的特徵空間中更有意義。
       所以呢,我們需要記得LDA的多用途,(1)聚類,(2)降緯,(3)特徵生成,一舉多得,典型的多面手。

對參數進行調試

online 方法setMaxIter

//對迭代次數進行循環
for(i<-Array(5,10,20,40,60,120,200,500)){
    val lda=new LDA()
                .setK(3)
                .setTopicConcentration(3)
                .setDocConcentration(3)
                .setOptimizer("online")
                .setCheckpointInterval(10)
                .setMaxIter(i)
    val model=lda.fit(dataset_lpa) 

    val ll = model.logLikelihood(dataset_lpa) 
    val lp = model.logPerplexity(dataset_lpa)

    println(s"$i $ll")
    println(s"$i $lp")
 }

可以得到如下的結果:logPerplexity在減小,LogLikelihood在增加,最大迭代次數需要設置50次以上,才能收斂:
這裏寫圖片描述
這裏寫圖片描述

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.
       由於這些參數都有明確的設置規則,因此也就不存在調優的問題了,計算出一個固定的值就可以了。但是我們還是實驗下:

//EM 方法,分析setDocConcentration的影響,計算(50/k)+1=50/5+1=11
for(i<-Array(1.2,3,5,7,9,11,12,13,14,15,16,17,18,19,20)){
    val lda=new LDA()
                .setK(5)
                .setTopicConcentration(1.1)
                .setDocConcentration(i)
                .setOptimizer("em")                
                .setMaxIter(30)

    val model=lda.fit(dataset_lpa) 
    val lp = model.logPerplexity(dataset_lpa)
    println(s"$i $lp") 
    }

可以看出果然DocConcentration>=11後,logPerplexity就不再下降了。
這裏寫圖片描述
在確定DocConcentration=11後,繼續對topicConcentration分析,發現logPerplexity對topicConcentration不敏感。

1.1          2.602768469
1.2          2.551084142
1.5          2.523405179
2.0          2.524881353
5             2.575868552

Online Variational Bayes
       (1)docConcentration: 可以通過傳遞一個k維等價於Dirichlet參數的向量作爲非對稱先驗。值應該>=0。向量-1表示默認,k維向量值取(1.0/k)。
       (2)topicConcentration: 只支持對稱先驗。值必須>=0。-1表示默認,取值爲(1.0/k)。
       docConcentration: Asymmetric priors can be used by passing in a vector with values equal to the Dirichlet parameter in each of the k dimensions. Values should be >=0>=0. Providing Vector(-1) results in default behavior (uniform k dimensional vector with value (1.0/k)(1.0/k))
   topicConcentration: Only symmetric priors supported. Values must be >=0>=0. Providing -1 results in defaulting to a value of (1.0/k)(1.0/k).

運行LDA的小技巧

       (1)確保迭代次數足夠多。這個前面已經講過了。前期的迭代返回一些無用的(極其相似的)話題,但是繼續迭代多次後結果明顯改善。我們注意到這對EM算法尤其有效。
       (2)對於數據中特殊停用詞的處理方法,通常的做法是運行一遍LDA,觀察各個話題,挑出各個話題中的停用詞,把他們濾除,再運行一遍LDA。
       (3)確定話題的個數是一門藝術。有些算法可以自動選擇話題個數,但是領域知識對得到好的結果至關重要。
       (4)特徵變換類的Pipeline API對於LDA的文字預處理工作極其有用;重點查看Tokenizer,StopwordsRemover和CountVectorizer接口.
       對文本的預處理,還可以參考我的另外兩篇文章《Spark2.0 特徵提取、轉換、選擇之一:數據規範化…》《Spark2.0 特徵提取、轉換、選擇之二:特徵選擇、文本處理…》。

參考文獻:
(1)Spark document
(2) zouxy09的CSDN 從最大似然到EM算法淺解
http://blog.csdn.net/zouxy09/article/details/8537620/
(3)4 步理解主題模型LDA http://www.tuicool.com/articles/reaIra6
(4)LDA主題模型與推薦系統 http://www.jianshu.com/p/50295398d802
(5)主題模型-LDA淺析 huagong_adu的CSDN博客
http://blog.csdn.net/huagong_adu/article/details/7937616/
(6)大規模主題模型:對Spark LDA算法的改進
http://www.csdn.net/article/2015-11-02/2826097
(7)Spark LDA pirage的CSDN博客
http://blog.csdn.net/pirage/article/details/50219323
(8)一篇非常簡潔的但是清晰明瞭的概念主題模型簡記
http://www.aichengxu.com/view/680260
(9) LDA主題模型評估方法–Perplexity
http://blog.csdn.net/pirage/article/details/9368535
(10) Spark MLlib LDA 源碼解析
http://blog.csdn.net/sunbow0/article/details/47662603
(11)《模式識別》 希臘Sergios Theodoridis等著
(12)數據挖掘經典算法——最大期望算法http://www.cnblogs.com/yahokuma/p/3794905.html
(13)極大似然估計和貝葉斯估計 http://blog.sciencenet.cn/blog-520608-703219.html
(14)最大似然估計(MLE)和最大後驗概率(MAP)http://www.cnblogs.com/liliu/archive/2010/11/24/1886110.html
(15)自然語言處理之LDA http://www.tuicool.com/articles/nQR3Yzf
(16)MCMC(Markov Chain Monte Carlo) and Gibbs Sampling http://www.cnblogs.com/ywl925/archive/2013/06/05/3118875.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章