1. 程式人生 > >文字相似度

文字相似度

前言

在自然語言處理過程中,經常會涉及到如何度量兩個文字之間的相似性,我們都知道文字是一種高維的語義空間,如何對其進行抽象分解,從而能夠站在數學角度去量化其相似性。而有了文字之間相似性的度量方式,我們便可以利用劃分法的K-means、基於密度的DBSCAN或者是基於模型的概率方法進行文字之間的聚類分析;另一方面,我們也可以利用文字之間的相似性對大規模語料進行去重預處理,或者找尋某一實體名稱的相關名稱(模糊匹配)。而衡量兩個字串的相似性有很多種方法,如最直接的利用hashcode,以及經典的主題模型或者利用詞向量將文字抽象為向量表示,再通過特徵向量之間的歐式距離或者皮爾森

距離進行度量。本文圍繞文字相似性度量的主題,從最直接的字面距離的度量到語義主題層面的度量進行整理總結,並將平時專案中用到的文字相似性程式碼進行了整理,如有任何紕漏還請指出,我會第一時間改正^v^。(ps.平時用的Java和scala較多,本文主要以Java為例。)

字面距離

提到如何比較兩個字串,我們從最初程式設計開始就知道:字串有字元構成,只要比較比較兩個字串中每一個字元是否相等便知道兩個字串是否相等,或者更簡單一點將每一個字串通過雜湊函式對映為一個雜湊值,然後進行比較。但是這種方法有一個很明顯的缺點,就是過於“硬”,對於相似性的度量其只有兩種,0不相似,1相似,哪怕兩個字串只有一個字元不相等也是不相似,這在NLP的很多情況是無法使用的,所以下文我們就“軟”的相似性的度量進行整理,而這些方法僅僅考慮了兩個文字的字面距離,無法考慮到文字內在的語義內容。

common lang庫

文中在部分程式碼應用中使用了Apache提供的common lang庫,該庫包含很多Java標準庫中沒有的但卻很實用的函式。其maven引用如下:


   
  1. <dependency>
  2. <groupId>org.apache.commons</groupId>
  3. <
    artifactId>commons-lang3</artifactId>
  4. <version>3.4</version>
  5. </dependency>

相同字元數

在傳統的字串比較過程中,我們考慮字串中每個字元是否相等,並且考慮了字元出現的順序,如果不考慮字元出現的順序,我們可以利用兩個文字之間相同的字元數量,很簡單不再贅述,可以利用common lang中的getFuzzyDistance:

int dis = StringUtils.getFuzzyDistance(term, query, Locale.CHINA);
    

萊文斯坦距離(編輯距離)

定義

我們在學習動態規劃的時候,一個很經典的演算法便是計算兩個字串的編輯距離,即:

萊文斯坦距離,又稱Levenshtein距離,是編輯距離(edit distance)的一種。指兩個字串之間,由一個轉成另一個所需的最少編輯操作次數。許可的編輯操作包括將一個字元替換成另一個字元,插入一個字元,刪除一個字元。

例如將kitten一字轉成sitting:

  1. sitten (k→s)
  2. sittin (e→i)
  3. sitting (→g)

那麼二者的編輯距離為3。
俄羅斯科學家弗拉基米爾·萊文斯坦在1965年提出這個概念。

實現方式

我們可以利用common lang中StringUtils的函式來計算:


   
  1. int dis = StringUtils.getLevenshteinDistance(s1, s2);
  2. //實現
  3. public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
  4. if (s == null || t == null) {
  5. throw new IllegalArgumentException( "Strings must not be null");
  6. }
  7. int n = s.length(); // length of s
  8. int m = t.length(); // length of t
  9. if (n == 0) {
  10. return m;
  11. } else if (m == 0) {
  12. return n;
  13. }
  14. if (n > m) {
  15. // swap the input strings to consume less memory
  16. final CharSequence tmp = s;
  17. s = t;
  18. t = tmp;
  19. n = m;
  20. m = t.length();
  21. }
  22. int p[] = new int[n + 1]; //'previous' cost array, horizontally
  23. int d[] = new int[n + 1]; // cost array, horizontally
  24. int _d[]; //placeholder to assist in swapping p and d
  25. // indexes into strings s and t
  26. int i; // iterates through s
  27. int j; // iterates through t
  28. char t_j; // jth character of t
  29. int cost; // cost
  30. for (i = 0; i <= n; i++) {
  31. p[i] = i;
  32. }
  33. for (j = 1; j <= m; j++) {
  34. t_j = t.charAt(j - 1);
  35. d[ 0] = j;
  36. for (i = 1; i <= n; i++) {
  37. cost = s.charAt(i - 1) == t_j ? 0 : 1;
  38. // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
  39. d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
  40. }
  41. // copy current distance counts to 'previous row' distance counts
  42. _d = p;
  43. p = d;
  44. d = _d;
  45. }
  46. // our last action in the above loop was to switch d and p, so p now
  47. // actually has the most recent cost counts
  48. return p[n];
  49. }

Jaro距離

定義

Jaro Distance也是字串相似性的一種度量方式,也是一種編輯距離,Jaro 距離越高本文相似性越高;而Jaro–Winkler distance是Jaro Distance的一個變種。據說是用來判定健康記錄上兩個名字是否相同,也有說是是用於人口普查。從最初其應用我們便可看出其用法和用途,其定義如下:

其中

  • 是匹配數目(保證順序相同)
  • 字串長度
  • 是換位數目

其中t換位數目表示:兩個分別來自S1和S2的字元如果相距不超過

我們就認為這兩個字串是匹配的;而這些相互匹配的字元則決定了換位的數目t,簡單來說就是不同順序的匹配字元的數目的一半即為換位的數目t,舉例來說,MARTHA與MARHTA的字元都是匹配的,但是這些匹配的字元中,T和H要換位才能把MARTHA變為MARHTA,那麼T和H就是不同的順序的匹配字元,t=2/2=1。
而Jaro-Winkler則給予了起始部分就相同的字串更高的分數,他定義了一個字首p,給予兩個字串,如果字首部分有長度為 的部分相同,則Jaro-Winkler Distance為:

  • 是兩個字串的Jaro Distance
  • 是字首的相同的長度,但是規定最大為4
  • 則是調整分數的常數,規定不能超過0.25,不然可能出現dw大於1的情況,Winkler將這個常數定義為0.1

舉個簡單的例子:
計算s_1=DIXON,s_2=DICKSONX的距離

我們利用\lfloor \frac{max(|s_1|,|s_2|)}{2}-1 \rfloor可以得到一個匹配視窗距離為3,圖中黃色部分便是匹配視窗,其中1表示一個匹配,我們發現兩個X並沒有匹配,因為其超出了匹配視窗的距離3。我們可以得到:

其Jaro score為:

d_j=\frac{1}{3}(\frac{4}{5}+\frac{4}{8}+\frac{4-0}{4})=0.767

而計算Jaro–Winkler score,我們使用標準權重p=0.1,\ell=2,其結果如下:

實現方式

同樣我們可以利用common lang中的getJaroWinklerDistance函式來實現,注意這裡實現的是Jaro–Winkler distance


   
  1. double dis = StringUtils.getJaroWinklerDistance(reviewName.toLowerCase(), newsName.toLowerCase());
  2. //實現
  3. public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) {
  4. final double DEFAULT_SCALING_FACTOR = 0.1; //標準權重
  5. if (first == null || second == null) {
  6. throw new IllegalArgumentException( "Strings must not be null");
  7. }
  8. final double jaro = score(first,second); // 計算Jaro score
  9. final int cl = commonPrefixLength(first, second); // 計算公共字首長度
  10. final double matchScore = Math.round((jaro + (DEFAULT_SCALING_FACTOR * cl * ( 1.0 - jaro))) * 100.0)/ 100.0; // 計算 Jaro-Winkler score
  11. return matchScore;
  12. }

應用

在Wetest輿情監控中,我們在找尋遊戲名簡稱和全稱的對應關係時便使用到了Jaro-Winkler score進行衡量,其中我們將Jaro分數大於0.6的認為是相似文字,之後在總的相似文字中提取最相似的作為匹配項,實現效果還不錯:

其中冒號左邊是待匹配項,右邊是匹配項<遊戲名 詞頻,Jaro-Winkler score>,Jaro-Winkler score較高的一般都是正確的匹配項。

SimHash

定義

SimHash是一種區域性敏感hash,它也是Google公司進行海量網頁去重使用的主要演算法。
傳統的Hash演算法只負責將原始內容儘量均勻隨機地對映為一個簽名值,原理上僅相當於偽隨機數產生演算法。傳統的hash演算法產生的兩個簽名,如果原始內容在一定概率下是相等的;如果不相等,除了說明原始內容不相等外,不再提供任何資訊,因為即使原始內容只相差一個位元組,所產生的簽名也很可能差別很大。所以傳統的Hash是無法在簽名的維度上來衡量原內容的相似度,而SimHash本身屬於一種區域性敏感雜湊演算法,它產生的hash簽名在一定程度上可以表徵原內容的相似度。
我們主要解決的是文字相似度計算,要比較的是兩個文章是否相似,當然我們降維生成了hash簽名也是用於這個目的。看到這裡估計大家就明白了,我們使用的simhash就算把文章中的字串變成 01 串也還是可以用於計算相似度的,而傳統的hash卻不行。

我們可以來做個測試,兩個相差只有一個字元的文字串,“你媽媽喊你回家吃飯哦,回家羅回家羅” 和 “你媽媽叫你回家吃飯啦,回家羅回家羅”。
通過simhash計算結果為:
1000010010101101111111100000101011010001001111100001001011001011
1000010010101101011111100000101011010001001111100001101010001011
通過傳統hash計算為:
0001000001100110100111011011110
1010010001111111110010110011101

通過上面的例子我們可以很清晰的發現simhash的區域性敏感性,相似文字只有部分01變化,而hash值很明顯,即使變化很小一部分,也會相差很大。

基本流程

注:具體的事例摘自Lanceyan[10]的部落格《海量資料相似度計算之simhash和海明距離》

  1. 分詞,把需要判斷文字分詞形成這個文章的特徵單詞。最後形成去掉噪音詞的單詞序列併為每個詞加上權重,我們假設權重分為5個級別(1~5)。比如:“ 美國“51區”僱員稱內部有9架飛碟,曾看見灰色外星人 ” ==> 分詞後為 “ 美國(4) 51區(5) 僱員(3) 稱(1) 內部(2) 有(1) 9架(3) 飛碟(5) 曾(1) 看見(3) 灰色(4) 外星人(5)”,括號裡是代表單詞在整個句子裡重要程度,數字越大越重要。
  2. hash,通過hash演算法把每個詞變成hash值,比如“美國”通過hash演算法計算為 100101,“51區”通過hash演算法計算為 101011。這樣我們的字串就變成了一串串數字,還記得文章開頭說過的嗎,要把文章變為數字計算才能提高相似度計算效能,現在是降維過程進行時。
  3. 加權,通過 2步驟的hash生成結果,需要按照單詞的權重形成加權數字串,比如“美國”的hash值為“100101”,通過加權計算為“4 -4 -4 4 -4 4”;“51區”的hash值為“101011”,通過加權計算為 “ 5 -5 5 -5 5 5”。
  4. 合併,把上面各個單詞算出來的序列值累加,變成只有一個序列串。比如 “美國”的 “4 -4 -4 4 -4 4”,“51區”的 “ 5 -5 5 -5 5 5”, 把每一位進行累加, “4+5 -4+-5 -4+5 4+-5 -4+5 4+5” ==》 “9 -9 1 -1 1 9”。這裡作為示例只算了兩個單詞的,真實計算需要把所有單詞的序列串累加。
  5. 降維,把4步算出來的 “9 -9 1 -1 1 9” 變成 0 1 串,形成我們最終的simhash簽名。 如果每一位大於0 記為 1,小於0 記為 0。最後算出結果為:“1 0 1 0 1 1”。
    整個過程的流程圖為:

相似性度量

有了simhash值,我們需要來度量兩個文字間的相似性,就像上面的例子一樣,我們可以比較兩個simhash間0和1不同的數量。這便是漢明距離(Hamming distance)

在資訊理論中,兩個等長字串之間的漢明距離(英語:Hamming distance)是兩個字串對應位置的不同字元的個數。換句話說,它就是將一個字串變換成另外一個字串所需要替換的字元個數。
漢明重量是字串相對於同樣長度的零字串的漢明距離,也就是說,它是字串中非零的元素個數:對於二進位制字串來說,就是1的個數,所以11101的漢明重量是4。
例如:
1011101與1001001之間的漢明距離是2

一般在利用simhash進行文字相似度比較時,我們認為漢明距離小於3的文字是相似的。

儲存索引


儲存:

  1. 將一個64位的simhash簽名拆分成4個16位的二進位制碼。(圖上紅色的16位)
  2. 分別拿著4個16位二進位制碼查詢當前對應位置上是否有元素。(放大後的16位)
  3. 對應位置沒有元素,直接追加到連結串列上;對應位置有則直接追加到連結串列尾端。(圖上的 S1 — SN)

查詢:

  1. 將需要比較的simhash簽名拆分成4個16位的二進位制碼。
  2. 分別拿著4個16位二進位制碼每一個去查詢simhash集合對應位置上是否有元素。
  3. 如果有元素,則把連結串列拿出來順序查詢比較,直到simhash小於一定大小的值,整個過程完成。
  4. 在去重時,因為漢明距離小於3則為重複文字,那麼如果存在simhash相似的文字,對於四段simhash則至少有一段simhash是相同的,所以在去重時對於待判斷文字D,如果D中每一段的simhash都沒有相同的,那麼D為無重複文字。

原理:
借鑑hashmap演算法找出可以hash的key值,因為我們使用的simhash是區域性敏感雜湊,這個演算法的特點是隻要相似的字串只有個別的位數是有差別變化。那這樣我們可以推斷兩個相似的文字,至少有16位的simhash是一樣的。具體選擇16位、8位、4位,大家根據自己的資料測試選擇,雖然比較的位數越小越精準,但是空間會變大。分為4個16位段的儲存空間是單獨simhash儲存空間的4倍。

實現

在實際NLP的使用中,我利用Murmur3作為字串的64位雜湊值,用Java和spark分別實現了一個simhash的版本
我將原始碼放在了github上,如下連結:

github: xlturing/simhashJava

其中利用了結巴作為文字的分詞工具,Murmur3用來產生64位的hashcode。另外根據上述儲存方式,進行了simhash分段儲存,提高搜尋速度,從而進行高效查重。

應用

simhash從最一開始用的最多的場景便是大規模文字的去重,對於爬蟲從網上爬取的大規模語料資料,我們需要進行預處理,刪除重複的文件才能進行後續的文字處理和挖掘,那麼利用simhash是一種不錯的選擇,其計算複雜度和效果都有一個很好的折中。
但是在實際應用過程中,也發現一些badcase,完全無關的文字正好對應成了相同的simhash,精確度並不是很高,而且simhash更適用於較長的文字,但是在大規模語料進行去重時,simhash的計算速度優勢還是很不錯的。

語義相似性

在NLP中有時候我們度量兩個短文字或者說更直接的兩個詞語的相似性時,直接通過字面距離是無法實現的,如:中國-北京義大利-羅馬,這兩個短語之間的相似距離應該是類似的,因為都是首都與國家的關係;再比如(男人、男孩),(女人、女孩)應該是相同的關係,但是我們看其字面距離都是0。
想要做到語義層面的度量,我們需要用到機器學習建模,而自然語言的問題轉化為機器學習的首要問題便是找到一種方法把自然語言的符號數學化。

背景知識

在自然語言處理領域中,有兩大理論方向,一種是基於統計的經驗主義方法,另一種是基於規則的理性主義方法[15]。而隨著計算機效能的提升,以及網際網路發展而得到的海量語料庫,目前NLP的研究更多是基於統計的經驗主義方法。所以在本文討論的語義相似性中,也是從統計學的角度出發進行總結。

統計語言模型

對於統計語言模型而言,最基礎的理論便是貝葉斯理論(Bayes' theorem PS.關於貝葉斯理論強烈推薦:數學之美番外篇:平凡而又神奇的貝葉斯方法,一篇深入淺出的好文。另外推薦下自己師兄參與翻譯的作品《貝葉斯方法——概率程式設計與貝葉斯推斷》很全面的貝葉斯理論+實踐書籍)。對於大規模語料庫,我們可以通過詞頻的方式來獲取概率,例如100個句子中,出現了1次"Okay",那麼

而同樣的對於句子"An apple ate the chicken"我們可以認為其概率為0,因為這不符合我們說話的邏輯。
統計語言模型是用來計算一個句子的概率,其通常基於一個語料庫D來構建。如何表示一個句子的概率呢?我們用來表示一個基元(通常就是指詞語,也可以是字或短語),那麼對於一個由N個片語成的句子W可以表示為

那麼其聯合概率

就可以認為是該句子的概率,根據貝葉斯公式的鏈式法則可以得到:

其中條件概率p(\omega_1)p(\omega_2|\omega_1)p(\omega_3|\omega_1,\omega_2)...p(\omega_n|\omega_1...\omega_{n-1})便是語言模型的引數,如果我們把這些全部算出來,那麼一個句子的概率我們就能很輕易的得出。但是很明顯,這個引數的量是巨大的是無法計算的。這時我們可以將\omega_i|\omega_1...\omega_{i-1}對映到某個等價類E(\omega_i|\omega_1...\omega_{i-1}),從而降低引數數目。
ps.語料庫我們用C表示,而詞典D一般為語料中出現的所有不重複詞

n-gram模型

既然每個單詞依賴的單詞過多,從而造成了引數過多的問題,那麼我們就簡單點,假設每個單詞只與其前n-1個單詞有關,這便是n-1階Markov假設,也就是n-gram模型的基本思想。
那麼對於句子W的概率我們可以簡化如下:

那麼對於最簡單的一階情況也稱unigram或uni-gram或monogram(二階bigram 三階trigram)就簡單表示為

為了在句首和句尾能夠統一,我們一般會在句首加一個BOS標記,句尾加一個EOS標記,那麼對於句子"Mark wrote a book",其概率可以表示如下:

為了預估p(\omega_i|\omega_{i-1})條件概率,根據大數定理,簡單統計語料庫中\omega_{i-1},\omega_i出現的頻率,並進行歸一化。我們用c來表示頻率,那麼可表示如下:

p(\omega_i|\omega_{i-1})=\frac{c(\omega_{i-1}\omega_i)}{\sum_{\omega_i}c(\omega_{i-1}\omega_i)}

其中分母在unigram中就可以簡單認為是詞語\omega_{i-1}出現的次數。
在n-gram模型中還有一個很重要的問題就是平滑化,因為再大的語料庫都不可能涵蓋所有情況,考慮兩個問題:

  1. c(\omega_{i-1}\omega_i)=0那麼p(\omega_i|\omega_{i-1})=0就是0嗎?
  2. c(\omega_{i-1}\omega_i)=\sum_{\omega_i}c(\omega_{i-1}\omega_i)那麼p(\omega_i|\omega_{i-1})=0就是1嗎?

這顯然是不合理的,這就需要進行平滑,這裡不展開討論。
根據最大似然,我們可以得到:

其中C表示語料庫,Context(omega)表示詞語的上下文,而這裡對於n-gram模型Context(\omega)=\oemga^{i-1}_{i-n+1},取對數後的對數似然函式為:

從上式我們可以看出p(\omega|Context(\omega))可以看做是\omega關於Context(omega)的函式,即:

其中theta為待定引數集,通過語料庫訓練得到引數集後,F便確定了,我們不需要再儲存概率p(\omega|Context(\omega)),可以直接計算得到,而語言模型中很關鍵的就在於F的構造

詞向量

為了從使得計算機從語義層面理解人類語言,首先要做的就是將語言數學化,如何進行表示呢?人們便提出了詞向量的概念,即用一個向量來表示一個詞。

One-hot Representation

一種最簡單詞向量就是利用詞頻向量將高維的語義空間抽象成數學符號表示,向量長度為詞典的大小,這種表示方式非常直觀,但是容易造成維度災難,並且還是不能刻畫語義的資訊。

詞語表示

對於詞語而言,用一個向量來表示一個詞,最直觀簡單的方式就是將每個詞變為一個很長的向量,向量長度便是詞典的長度,其中絕大部分為0,只有一個維度為1代表了當前詞。
假設語料庫:“衝突容易引發戰爭”,那麼詞典為

  • D=[衝突,容易,引發,戰爭]
  • 衝突=[1,0,0,0]
  • 戰爭=[0,0,0,1]

每個詞都是含有一個1的n維向量(),這種方式我們壓縮儲存下,就是給每個詞語分配一個ID,通常實際變成我們最簡單的就是用hash值表示一個詞語。這種方式可以用在SVM、最大熵和CRF等等演算法中,完成NLP的大多數場景。例如,我們可以直接將
但是缺點很明顯,就是我們用這種方式依舊無法度量兩個詞的語義相似性,任意兩個詞之間都是孤立的,比如上面的衝突和戰爭是近義詞,但是卻沒有任何關聯性。

文件表示

同樣文件也可以用詞頻向量的形式來表示,一般我們會利用tf-idf作為每一個詞的特徵值,之後會挑選每篇文件比較重要的部分詞來表示一篇文件,拿遊戲來說,如下:
[王者榮耀, 陰陽師, 夢幻西遊]

  • doc1:[tf-idf(王者榮耀), tf-idf(陰陽師), tf-idf(夢幻西遊)]
  • doc2:[tf-idf(王者榮耀), tf-idf(陰陽師), tf-idf(夢幻西遊)]

然後我們就可以利用K-means等聚類演算法進行聚類分析,當然對於每篇文件,一般我們只會選取部分詞彙,因為如果詞彙過多可能造成NLP中常見的維度“災難”。這種方式在大多數NLP場景中都是適用的,但是由於這種表示往往是建立在高維空間,為了避免維度災難就要損失一定的語義資訊,這也是這種方法的弊端。

Distributed representation

另外一種詞向量的表示Distributed representation最早由 Hinton在 1986年提出。它是一種低維實數向量,這種向量一般長成這個樣子:
[0.792, −0.177, −0.107, 0.109, −0.542, …]
維度以 50 維和 100 維比較常見,當然了,這種向量的表示不是唯一的。
Distributed representation的關鍵點在於,將高維空間中的詞彙對映到一個低維的向量空間中,並且讓相關或者相似的詞,在距離上更接近(看到這裡大家有沒有想到普通hash以及simhash的區別呢?),這裡引用一張圖片(來自[13]):

圖中是英語和西班牙語通過訓練分別得到他們的詞向量空間,之後利用PCA主成分分析進行降維表示在二維座標圖中的。我們可以清晰的看出,對於兩種語系的一二三四五,在空間距離上竟是如此的相似,這就是Distributed representation詞向量表示的意義所在。
這種採用低維空間表示法,不但解決了維數災難問題,並且挖掘了word之間的關聯屬性,從而提高了向量語義上的準確度,下面我們討論的語言模型都是基於這種詞向量表示方式。
PS. 有時候也會出現Word Represention或 Word Embedding(所謂詞嵌入)的說法。另外我們這裡說的詞向量是在詞粒度進行分析,當然我們也可以在字粒度的字向量、句子粒度的句向量以及文件粒度的文件向量進行表示分析。

主題模型

在長文字的篇章處理中,主題模型是一種經典的模型,經常會用在自然語言處理、推薦演算法等應用場景中。本節從LDA的演變過程對LDA進行闡述,然後就LDA在長文字相似性的判斷聚類上做簡要說明。

LSA

首先對於一篇文件Document,詞語空間的一個詞頻向量如下:

其中每個維度表示某一詞語term在該文件中出現的次數,最終對於大量的訓練樣本,我們可以得到訓練樣本的矩陣X,如下圖:

LSA的基本思想,便是利用最基本的SVD奇異值分解,將高維語義空間對映到低維空間,其流程如下:

這樣對於訓練樣本中詞表的每一個term我們便得到了一個低維空間的向量表示。但LSA的顯著問題便是值考慮詞頻,並不區分同一詞語的不同含義

PLSA

LSA基於最基本的SVD分解,但缺乏嚴謹的數理統計邏輯,於是Hofmann提出了PLSA,其中P便是Probabilistic,其基本的假設是每個文件所表示的詞頻空間向量w服從多項式分佈(Multinomial distribution


簡單扯兩句多項式分佈:

  • 伯努利分佈Bernoulli distribution)我們從接觸概率論開始便知道,即所謂的投硬幣,其離散分佈如下:

    但是吊吊的數學家們總喜歡做一些優雅的讓人看不懂的事情,所以也可以寫作如下公式:

    其中k為0或者1

  • 二項分佈Binomial distribution):


    如果進行次投硬幣實驗,計算出現m次正面朝上的概率
    伯努利分佈是二項分佈中n=1時的特殊情況

  • Categorical分佈Categorical distribution),如果我們將投硬幣改成擲骰子,那麼原來一維向量x就會變成一個六維向量,其中每一維度為1表示出現該面,0表示沒出現,用數學表示即對於隨機變數X有k中情況,其中第種情況出現的概率為

    那麼我們可以得到其離散概率分佈如下:

    其中如果那麼為1,否則為0

  • 多項式分佈Multinomial distribution):與二項分佈類似,Categorical分佈進行N次試驗,便得到多項式分佈:

    同樣我們可以寫成吊吊的形式:

其中gamma函式:當n>0,則(ps.該形式與狄利克雷分佈(Dirichlet distribution)的形式非常相似,因為多項式分佈是狄利克雷分佈的共軛先驗)


OK簡單梳理了下過去的知識,PLSA假設每篇文件的詞頻向量服從Categorical分佈,那麼對於整個訓練樣本的詞頻矩陣W則服從多項式分佈。PLSA利用了aspect model,引入了潛在變數z(即所謂主題),使其變成一個混合模型(mixture model)。其圖模型如下:

其中表示文件集,Z便是PLSA中引入的隱含變數(主題/類別),表示詞表。表示單詞出現在文件的概率,表示文件中出現主題下的單