天然語言處理中的N-Gram模型

N-Gram(有時也稱爲N元模型)是天然語言處理中一個很是重要的概念,一般在NLP中,人們基於必定的語料庫,能夠利用N-Gram來預計或者評估一個句子是否合理。另一方面,N-Gram的另一個做用是用來評估兩個字符串之間的差別程度。這是模糊匹配中經常使用的一種手段。本文將今後開始,進而向讀者展現N-Gram在天然語言處理中的各類powerful的應用。java

  • 基於N-Gram模型定義的字符串距離
  • 利用N-Gram模型評估語句是否合理
  • 使用N-Gram模型時的數據平滑算法

歡迎關注白馬負金羈的博客 http://blog.csdn.net/baimafujinji,爲保證公式、圖表得以正確顯示,強烈建議你從該地址上查看原版博文。本博客主要關注方向包括:數字圖像處理、算法設計與分析、數據結構、機器學習、數據挖掘、統計分析方法、天然語言處理。算法


基於N-Gram模型定義的字符串距離

在天然語言處理時,最經常使用也最基礎的一個操做是就是「模式匹配」,或者稱爲「字符串查找」。而模式匹配(字符串查找)又分爲精確匹配和模糊匹配兩種。apache

所謂精確匹配,你們應該並不陌生,好比咱們要統計一篇文章中關鍵詞 「information」 出現的次數,這時所使用的方法就是精確的模式匹配。這方面的算法也比較多,並且應該是計算機相關專業必修的基礎課中都會涉及到的內容,例如KMP算法、BM算法和BMH算法等等。markdown

另一種匹配就是所謂的模糊匹配,它的應用也隨處可見。例如,通常的文字處理軟件(例如,Microsoft Word等)都會提供拼寫檢查功能。當你輸入一個錯誤的單詞,例如 「 informtaion」 時,系統會提示你是否要輸入的詞實際上是 「information」 。將一個可能錯拼單詞映射到一個推薦的正確拼寫上所採用的技術就是模糊匹配。數據結構

模糊匹配的關鍵在於如何衡量兩個長得很像的單詞(或字符串)之間的「差別」。這種差別一般又稱爲「距離」。這方面的具體算法有不少,例如基於編輯距離的概念,人們設計出了 Smith-Waterman 算法和Needleman-Wunsch 算法,其中後者仍是歷史上最先的應用動態規劃思想設計的算法之一。如今Smith-Waterman 算法和Needleman-Wunsch 算法在生物信息學領域也有重要應用,研究人員經常用它們來計算兩個DNA序列片斷之間的「差別」(或稱「距離」)。甚至於在LeetCode上也有一道「No.72 Edit Distance」,其本質就是在考察上述兩種算法的實現。可見相關問題離咱們並不遙遠。機器學習

N-Gram在模糊匹配中的應用

事實上,筆者在新出版的《算法之美——隱匿在數據結構背後的原理》一書中已經詳細介紹了包括Needleman-Wunsch算法、Smith-Waterman算法、N-Gram算法、Soundex算法、Phonix算法等在內的多種距離定義算法(或模糊匹配算法)。而今天爲了引出N-Gram模型在NLP中的其餘應用,咱們首先來介紹一下如何利用N-Gram來定義字符串之間的距離。函數

咱們除了能夠定義兩個字符串之間的編輯距離(一般利用Needleman-Wunsch算法或Smith-Waterman算法)以外,還能夠定義它們之間的N-Gram距離。N-Gram(有時也稱爲N元模型)是天然語言處理中一個很是重要的概念。假設有一個字符串 ss,那麼該字符串的N-Gram就表示按長度 N 切分原詞獲得的詞段,也就是 ss 中全部長度爲 N 的子字符串。設想若是有兩個字符串,而後分別求它們的N-Gram,那麼就能夠從它們的共有子串的數量這個角度去定義兩個字符串間的N-Gram距離。可是僅僅是簡單地對共有子串進行計數顯然也存在不足,這種方案顯然忽略了兩個字符串長度差別可能致使的問題。好比字符串 girl 和 girlfriend,兩者所擁有的公共子串數量顯然與 girl 和其自身所擁有的公共子串數量相等,可是咱們並不能據此認爲 girl 和girlfriend 是兩個等同的匹配。工具

爲了解決該問題,有學者便提出以非重複的N-Gram分詞爲基礎來定義 N-Gram距離這一律念,能夠用下面的公式來表述: post

 
|GN(s)|+|GN(t)|2×|GN(s)GN(t)||GN(s)|+|GN(t)|−2×|GN(s)∩GN(t)|

此處, |GN(s)||GN(s)| 是字符串 ss 的 N-Gram集合,N 值通常取2或者3。以 N = 2 爲例對字符串Gorbachev和Gorbechyov進行分段,可得以下結果(咱們用下畫線標出了其中的公共子串)。 

 


 

結合上面的公式,便可算得兩個字符串之間的距離是8 + 9 − 2 × 4 = 9。顯然,字符串之間的距離越小,它們就越接近。當兩個字符串徹底相等的時候,它們之間的距離就是0。

 

利用N-Gram計算字符串間距離的Java實例

《算法之美——隱匿在數據結構背後的原理》一書中,咱們給出了在C++下實現的計算兩個字符串間N-Gram距離的函數,鑑於全書代碼已經在本博客中發佈,這裏再也不重複列出。事實上,不少語言的函數庫或者工具箱中都已經提供了封裝好的計算 N-Gram 距離的函數,下面這個例子演示了在Java中使用N-Gram 距離的方法。學習

針對這個例子,這裏須要說明的是:

  • 調用函數須要引用lucene的JAR包,我所使用的是lucene-suggest-5.0.0.jar
  • 前面咱們所給出的算法計算所得爲一個絕對性的距離分值。而Java中所給出的函數在此基礎上進行了歸一化,也就是說所得之結果是一個介於0~1之間的浮點數,即0的時候表示兩個字符串徹底不一樣,而1則表示兩個字符串徹底相同。
import org.apache.lucene.search.spell.*;

public class NGram_distance {

    public static void main(String[] args) {

        NGramDistance ng = new NGramDistance();
        float score1 = ng.getDistance("Gorbachev", "Gorbechyov");
        System.out.println(score1);
        float score2 = ng.getDistance("girl", "girlfriend");
        System.out.println(score2);
    }
}

有興趣的讀者能夠在引用相關JAR包以後在Eclipse中執行上述Java程序,你會發現,和咱們預期的同樣,字符串Gorbachev和Gorbechyov所得之距離評分較高(=0.7),說明兩者很接近;而girl和girlfriend所得之距離評分並不高(=0.3999),說明兩者並不很接近。


利用N-Gram模型評估語句是否合理

從如今開始,咱們所討論的N-Gram模型跟前面講過N-Gram模型從外在來看已經大不相同,可是請注意它們內在的聯繫(或者說本質上它們仍然是統一的概念)。

爲了引入N-Gram的這個應用,咱們從幾個例子開始。 
首先,從統計的角度來看,天然語言中的一個句子 ss 能夠由任何詞串構成,不過幾率 P(s)P(s) 有大有小。例如:

  • s1s1 = 我剛吃過晚飯
  • s2s2 = 剛我過晚飯吃

顯然,對於中文而言 s1s1 是一個通順而有意義的句子,而s2s2 則不是,因此對於中文來講,P(s1)>P(s2)P(s1)>P(s2) 。但不一樣語言來講,這兩個機率值的大小可能會反轉。

其次,另一個例子是,若是咱們給出了某個句子的一個節選,咱們其實能夠可以猜想後續的詞應該是什麼,例如

  • the large green __ . Possible answer may be 「mountain」 or 「tree」 ?
  • Kate swallowed the large green __ . Possible answer may be 「pill」 or 「broccoli」 ?

顯然,若是咱們知道這個句子片斷更多前面的內容的狀況下,咱們會獲得一個更加準確的答案。這就告訴咱們,前面的(歷史)信息越多,對後面未知信息的約束就越強。

若是咱們有一個由 mm 個詞組成的序列(或者說一個句子),咱們但願算得機率 P(w1,w2,,wm)P(w1,w2,⋯,wm) ,根據鏈式規則,可得 

 
P(w1,w2,,wm)=P(w1)P(w2|w1)P(w3|w1,w2)P(wm|w1,,wm1)P(w1,w2,⋯,wm)=P(w1)P(w2|w1)P(w3|w1,w2)⋯P(wm|w1,⋯,wm−1)

這個機率顯然並很差算,不妨利用馬爾科夫鏈的假設,即當前這個詞僅僅跟前面幾個有限的詞相關,所以也就沒必要追溯到最開始的那個詞,這樣即可以大幅縮減上訴算式的長度。即 
 
P(wi|w1,,wi1)=P(wi|win+1,,wi1)P(wi|w1,⋯,wi−1)=P(wi|wi−n+1,⋯,wi−1)

特別地,對於 nn 取得較小值的狀況 
當 n=1n=1, 一個一元模型(unigram model)即爲 
 
P(w1,w2,,wm)=i=1mP(wi)P(w1,w2,⋯,wm)=∏i=1mP(wi)

當 n=2n=2, 一個二元模型(bigram model)即爲 
 
P(w1,w2,,wm)=i=1mP(wi|wi1)P(w1,w2,⋯,wm)=∏i=1mP(wi|wi−1)

當 n=3n=3, 一個三元模型(trigram model)即爲 
 
P(w1,w2,,wm)=i=1mP(wi|wi2wi1)P(w1,w2,⋯,wm)=∏i=1mP(wi|wi−2wi−1)

接下來的思路就比較明確了,能夠利用最大似然法來求出一組參數,使得訓練樣本的機率取得最大值。

 

  • 對於unigram model而言,其中c(w1,..,wn)c(w1,..,wn) 表示 n-gram w1,..,wnw1,..,wn 在訓練語料中出現的次數,MM 是語料庫中的總字數(例如對於 yes no no no yes 而言,M=5M=5) 
     
    P(wi)=C(wi)MP(wi)=C(wi)M
  • 對於bigram model而言, 
     
    P(wi|wi1)=C(wi1wi)C(wi1)P(wi|wi−1)=C(wi−1wi)C(wi−1)
  • 對於nn-gram model而言, 
     
    P(wi|win1,,wi1)=C(win1,,wi)C(win1,,wi1)P(wi|wi−n−1,⋯,wi−1)=C(wi−n−1,⋯,wi)C(wi−n−1,⋯,wi−1)

來看一個具體的例子,假設咱們如今有一個語料庫以下,其中<s1><s2><s1><s2> 是句首標記,</s2></s1></s2></s1> 是句尾標記: 

 
<s1><s2>yesnonononoyes</s2></s1><s1><s2>nononoyesyesyesno</s2></s1><s1><s2>yesnonononoyes</s2></s1><s1><s2>nononoyesyesyesno</s2></s1>

下面咱們的任務是來評估以下這個句子的機率: 
 
<s1><s2>yesnonoyes</s2></s1><s1><s2>yesnonoyes</s2></s1>

咱們來演示利用trigram模型來計算機率的結果 
 
P(yes|<s1><s2>)=12,P(no|<s2>yes)=1P(no|yesno)=12,P(yes|nono)=25P(</s2>|noyes)=12,P(</s1>|yes</s2>)=1P(yes|<s1><s2>)=12,P(no|<s2>yes)=1P(no|yesno)=12,P(yes|nono)=25P(</s2>|noyes)=12,P(</s1>|yes</s2>)=1

因此咱們要求的機率就等於: 
 
12×1×12×25×12×1=0.0512×1×12×25×12×1=0.05

 

再舉一個來自文獻[1]的例子,假設如今有一個語料庫,咱們統計了下面一些詞出現的數量

 


 

下面這個機率做爲其餘一些已知條件給出: 
 
P(i|<s>)=0.25P(english|want)=0.0011P(food|english)=0.5P(</s>|food)=0.68P(i|<s>)=0.25P(english|want)=0.0011P(food|english)=0.5P(</s>|food)=0.68

下面這個表給出的是基於Bigram模型進行計數之結果 

 

例如,其中第一行,第二列 表示給定前一個詞是 「i」 時,當前詞爲「want」的狀況一共出現了827次。據此,咱們即可以算得相應的頻率分佈表以下。 

 

由於咱們從表1中知道 「i」 一共出現了2533次,而其後出現 「want」 的狀況一共有827次,因此P(want|i)=827/25330.33P(want|i)=827/2533≈0.33 
如今設s1=<s>iwantenglishfood</s>s1=「<s>iwantenglishfood</s>」 ,則能夠算得 
 
P(s1)=P(i|<s>)P(want|i)P(english|want)P(food|english)P(</s>|food)=0.25×0.33×0.0011×0.5×0.68=0.000031P(s1)=P(i|<s>)P(want|i)P(english|want)P(food|english)P(</s>|food)=0.25×0.33×0.0011×0.5×0.68=0.000031

 


使用N-Gram模型時的數據平滑算法

有研究人員用150萬詞的訓練語料來訓練 trigram 模型,而後用一樣來源的測試語料來作驗證,結果發現23%的 trigram 沒有在訓練語料中出現過。這其實就意味着上一節咱們所計算的那些機率有空爲 0,這就致使了數據稀疏的可能性,咱們的表3中也確實有些爲0的狀況。對語言而言,因爲數據稀疏的存在,極大似然法不是一種很好的參數估計辦法。

這時的解決辦法,咱們稱之爲「平滑技術」(Smoothing)或者 「減值」 (Discounting)。其主要策略是把在訓練樣本中出現過的事件的機率適當減少,而後把減少獲得的機率密度分配給訓練語料中沒有出現過的事件。實際中平滑算法有不少種,例如: 
  ▸ Laplacian (add-one) smoothing 
  ▸ Add-k smoothing 
  ▸ Jelinek-Mercer interpolation 
  ▸ Katz backoff 
  ▸ Absolute discounting 
  ▸ Kneser-Ney

對於這些算法的詳細介紹,咱們將在後續的文章中結合一些實例再來進行討論。


A Final Word

若是你能從前面那些繁冗、複雜的概念和公式中挺過來,恭喜你,你對N-Gram模型已經有所認識了。儘管,咱們還沒來得及探討平滑算法(但它即將出如今個人下一篇博文裏,若是你以爲還未過癮的話),可是其實你已經掌握了一個相對powerful的工具。你能夠能會問,在實踐中N-Gram模型有哪些具體應用,做爲本文的結束,主頁君便在此補充幾個你曾見過的或者曾經好奇它是如何實現的例子。

Eg.1 
搜索引擎(Google或者Baidu)、或者輸入法的猜測或者提示。你在用百度時,輸入一個或幾個詞,搜索框一般會如下拉菜單的形式給出幾個像下圖同樣的備選,這些備選實際上是在猜測你想要搜索的那個詞串。再者,當你用輸入法輸入一個漢字的時候,輸入法一般能夠聯繫出一個完整的詞,例如我輸入一個「劉」字,一般輸入法會提示我是否要輸入的是「劉備」。經過上面的介紹,你應該可以很敏銳的發覺,這實際上是以N-Gram模型爲基礎來實現的,若是你能有這種覺悟或者想法,那我不得不恭喜你,都學會搶答了!

 


 

 

Eg.2 
某某做家或者語料庫風格的文本自動生成。這是一個至關有趣的話題。來看下面這段話(該例子取材自文獻【1】):

「You are uniformly charming!」 cried he, with a smile of associating and now and then I bowed and they perceived a chaise and four to wish for.

你應該尚未感受到它有什麼異樣吧。但事實上這並非由人類寫出的句子,而是計算機根據Jane Austen的語料庫利用trigram模型自動生成的文段。(Jane Austen是英國著名女做家,表明做有《傲慢與偏見》等)

再來看兩個例子,你是否能看出它們是按照哪位文豪(或者語料庫)的風格生成的嗎?

  • This shall forbid it should be branded, if renown made it empty.
  • They also point to ninety nine point six billion dollars from two hundred four oh three percent of the rates of interest stores as Mexico and Brazil on market conditions.

答案是第一個是莎士比亞,第二個是華爾街日報。最後一個問題留給讀者思考,你以爲上面兩個文段所運用的n-gram模型中,n應該等於多少?


推薦閱讀和參考文獻:

[1] Speech and Language Processing. Daniel Jurafsky & James H. Martin, 3rd. Chapter 4 
[2] 本文中的一些例子和描述來自 北京大學 常寶寶 以及 The University of Melbourne 「Web Search and Text Analysis」 課程的幻燈片素材

來自 https://blog.csdn.net/baimafujinji/article/details/51281816
相關文章
相關標籤/搜索