LDA模型簡介、源碼分析及實驗

一  概率主題模型簡介

    隱含狄利克雷分佈(LatentDirichlet Allocation,LDA)[1]是一種文檔生成模型,包含文檔、主題和詞三層結構。如圖1所示,LDA假設每篇文檔由若干隱含的主體組成,每個主題下有一系列與主題相關的詞彙。當要生成一篇文章時,是通過以一定的概率選擇某個主題,然後再以一定的概率選擇主題下某個詞語。LDA是一種非監督機器學習技術,可以用來發現大規模文檔集合或者語料庫中隱含的主題分佈信息。與關鍵詞匹配技術相比,LDA主題模型更關注文檔或語料的語義信息,它將文檔歸納出若干主題,然後根據文檔主題計算相似性,因此,LDA主題模型是一種更抽象層次的匹配技術。


圖1  文檔主題分佈、主題詞分佈舉例

    理解LDA模型主要理解圖2所示文檔生成的兩個物理過程:

    1)α—>θ—>z:以一定的概率生成文檔中詞的主題編號z;

    2)β—>φ—>w:以一定的概率選擇編號爲z的主題下某個詞。

    如果一篇文檔由n個詞,則重複上述兩個步驟n次,最終生成一篇文檔。其中α與β是狄利克雷分佈先驗參數,人工調參。


圖2  LDA文檔生成模型的兩個物理過程


    兩個物理過程對應到文檔中的效果如圖3 所示:


圖3  LDA物理分解過程與文檔的主題及詞的對應關係


    現實中,觀測數據僅僅是文檔,目的是推測文檔的潛在主題結構,如圖4所示,進一步說,已知的是左邊的矩陣,要求解右邊兩個矩陣:


圖4  文檔生成模型


    這裏介紹學習LDA模型時使用的是吉布斯抽樣方法[2]。LDA建模過程可以看做是發現每個文檔的混合主題p(z|d),其中d表示文檔,z表示文檔中的混合主題。而每個主題又可以看做是一系列相關詞的混合分佈,這一過程可以表示爲:
          
其中,表示文檔d中出現詞的概率,表示隱含主題j中出現的概率,表示文檔d屬於主題j的概率。吉布斯抽樣方法爲文檔的每個詞進行多次迭代,每次迭代都以下列公式2爲詞採樣一個新的主題,直到圖4中參數φ與θ收斂。

其中,表示兩個矩陣,分別記錄了所有詞語i歸入主題j的次數和文檔i中歸入主題j的詞語的數目,表示除當前主題外所有主題-詞和文檔-主題的分佈,αβ是狄利克雷先驗的超參數,用於平滑模型。於是,公式(1)的後驗概率可以按下列公式(3)和公式(4)計算得出:


公式(3)表示文檔的主題分佈,公式(4)表示主題的詞分佈。通過公式(3)(4)可確定文檔的主題分佈及主題的詞分佈。


二 源碼分析

    這裏使用的源碼爲JGibbLDA,使用時根據需要可以改進源碼的實現細節。

     A  具體訓練LDA模型有如下幾個步驟:

          //加載語料庫

         1) Corpus corpus = Corpus.load("data/mashups_apis");

         //初始化一個LDA模型

         2) LdaGibbsSampler ldaGibbsSampler = new LdaGibbsSampler(corpus.getDocument(), corpus.getVocabularySize());

         //抽樣生成10個主題

         3)ldaGibbsSampler.gibbs(10);

         // 保存本次 生成的模型

         4)ldaGibbsSampler.saveModel(corpus.getVocabulary(),"test");

     B  上述4個步驟的具體實現思想

         1)將文檔進行預處理(去停用詞,分詞等等),建立詞庫,爲文檔中的每個詞進行編號,因此加載語料庫後實際上會生成一 個mxn的矩陣,m表示語料庫中的文檔數目,n表示詞庫的大小,矩陣中的值表示對應文檔中詞在詞庫中的編號(相同的詞編號一樣);

         2)初始化一個LDA模型(面向對象的編程思想),初始化模型的先驗參數等等;

         3)按照公式2進行迭代抽樣每篇文檔中每個詞的屬於的主題,更新φ與θ矩陣,直到φ與θ收斂;

         4)保存φ與θ矩陣結果(多次的平均結果),算法結束。

     C  算法部分源碼

    //folderPath 保存語料的文件夾路徑  文件夾下每個文檔已經通過預處理

    public static Corpus load(String folderPath) throws IOException
    {
        Corpus corpus = new Corpus();
        File folder = new File(folderPath);
        int count = 0;
        
        for (File file : folder.listFiles())
        {
        ++count;
        String filename = file.getName();
            BufferedReader br = new BufferedReader(new FileReader(file));
            String line;
            List<String> wordList = new LinkedList<String>();//存放當前文檔裏面的所有詞彙
            while ((line = br.readLine()) != null)
            {
                String[] words = line.split(" ");
                for (String word : words)
                {
                    if (word.trim().length() < 2) continue;
                    wordList.add(word);
                }
            }
            br.close();
            corpus.addDocument(wordList,filename);//保存當前文檔的每個詞(將wordList加入詞庫,每個詞對應詞庫中的一個編號)
        }
        System.out.println("共 " + count + " 個文檔被加載。");
        if (corpus.getVocabularySize() == 0) return null;
        
        return corpus;
    }


    //重新生成每個詞的主題

     private int sampleFullConditional(int m, int n)
    {
        // remove z_i from the count variables  先將這個詞從計數器中抹掉
        int topic = z[m][n];
        nw[documents[m][n]][topic]--;
        nd[m][topic]--;
        nwsum[topic]--;
        ndsum[m]--;


        // do multinomial sampling via cumulative method: 通過多項式方法採樣多項式分佈
        double[] p = new double[K];
        for (int k = 0; k < K; k++)
        {
            p[k] = (nw[documents[m][n]][k] + beta) / (nwsum[k] + V * beta)
                    * (nd[m][k] + alpha) / (ndsum[m] + K * alpha);
        }
        // cumulate multinomial parameters  累加多項式分佈的參數
        for (int k = 1; k < p.length; k++)
        {
            p[k] += p[k - 1];
        }
        // scaled sample because of unnormalised p[] 正則化
        double u = Math.random() * p[K - 1];
        for (topic = 0; topic < p.length; topic++)
        {
            if (u < p[topic])
                break;
        }


        // add newly estimated z_i to count variables   將重新估計的該詞語加入計數器
        nw[documents[m][n]][topic]++;
        nd[m][topic]++;
        nwsum[topic]++;
        ndsum[m]++;
        return topic;
    }


三  實驗

    本實驗主要分析短文本的主題分佈,從programmableweb.com爬取的數據經過處理後包含6693個Mashup和9122個API,每個Mashup或者API都有一個短文本描述,因此訓練LDA模型輸入爲6693+9122個短文本,目標是分別得到這些短文本的主題分佈,及主題下詞的分佈情況,以及上述討論的φ與θ。

    試驗中設置訓練主題數目爲10,超參數α=2.0以及β=0.1,最終得到φ與θ矩陣如下:


圖5  φ矩陣部分結果(主題下詞的分佈,共10個主題,因此矩陣行爲10,列爲詞庫大小)


        圖6  θ矩陣部分結果(文檔的主題分佈,共10個主題,因此矩陣列爲10,行爲語料庫中文檔數目)


四 文章引用

[1] Bleid D.M, Ng A.Y, Jordan M.I. Latentdirichlet allocation[J]. Journal of Machine Learning Research, 2003, 3(1) :993-1022.

[2] Heinrich G. Parameter estimation fortext analysis. Technical report, vsonix.GmbH and University of Leipzig,Germany, 2009.






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