利用條件隨機場模型進行中文分詞


      中文分詞的方法非常多,基於詞庫是最基本的,但是當前各大互聯網公司基本上不會僅僅依賴於詞庫的分詞,一般以機器學習的分詞為主,詞庫分詞的方式為輔。在很久以前,我提過利用隱馬爾科夫模型進行中文分詞,條件隨機場其實是隱馬爾科夫模型的一次升級版本,網上有很多關於條件隨機場模型的分詞,但是基本上很難看懂,也許是論文的緣故,那些作者習慣了一上來就是一堆復雜的公式,我也看了一些,獲取有些作者自己都沒搞懂,就弄了一篇論文。本文從實踐的角度,提供一種基於條件隨機場模型的中文分詞解決方案。

      第一步:准備語料庫。

      首先,你必須得准備一個已經分好詞的語料庫,用於機器學習,如下圖所示:

     條件隨機場分詞1

      如果你沒有,可以在這里下載

      第二步:初步語料庫特征學習

      和隱馬爾科夫模型一樣,條件隨機場也是基於學習字的狀態來進行狀態分析的,對於一個字來說,它有4個狀態,分別是:詞頭(Begin)、詞中(Middle)、詞尾(End)、單字成詞(Single),簡稱B,M,E,S。

      因此需要把第一步的語料庫,分析出每一個字的狀態,例如:“收益”需要改進為:“收|B 益|E”, 通過將語料庫的每一個分好的詞,添加其狀態信息,如下圖所示:

      條件隨機場分詞2

      當然,如果你比較懶,也沒有關系,我這里提供好已經分析完畢的數據,可以在這里下載

      第三步:特征學習

      有了第二步的初步學習,第三步就相對容易多了,特征學習是整個過程中非常重要的部分,在進行特征學習之前,必須弄清楚一個問題,要學習哪些特征?如下:

      1. 這一個字一共在語料庫中出現的次數是多少?例如“我”字一共出現了256次。

      2. 這一個字,出現為詞頭(B)、詞中(M)、詞尾(E)、單字成詞(S)的概率是多少?即為在256出現“我”字的時候,“我”作為詞頭的概率是多少,詞中的概率是多少,依次類推。

      3. 這一個字,當為詞頭(B)的時候,它轉移到下一個詞的狀態概率是多少?每一個字都有屬於自己的狀態,但是這個字的后面一個字,也有屬於自己的狀態,那么當前字的狀態,到下一個字的狀態(或許是B、M、E、S之一)的概率是多少。例“我”字,當“我”的狀態為B的時候,后面跟的字中,狀態為B的為0個,狀態為M的為10個,狀態為E的為20個,狀態為S的0個。依次統計“我”的狀態為M、E、S的時候,下一字的狀態。此過程俗稱:狀態轉移概率計算。此項會形成一個4X4的矩陣。

      截至前面三個特征學習,也許你會感覺與隱馬爾科夫模型的方式沒有太大區別,但是從理論上研究,條件隨機場的准確率一定是高於隱馬爾科夫模型的。是因為條件隨機場會學習上下文關系,也就是多計算了,當一個字出現的時候,它的前一個字是什么,后一個字是什么,這個概率是多少,也就是我們第四個特征學習。

     4. 這一個字出現的時候,后面字出現的是什么,概率為多少?例如當狀態為B的“我”,下一個字是“們”的概率為67.9%,例如狀態為S的“我”,上一個字是“的”的概率為21%,下一個字是“愛”的概率為17.8%等等,記錄每一個字在四種狀態下上下文關系,是非常重要的一步。這一步中,我們僅僅記錄了上一個字和下一個字的上下文關系,條件允許的情況下,我們可以記錄上兩個字和下兩個字的上下文關系。

     利用代碼,就是如下示例:

/**
     * Feature for each word.
     * 
     * @author liufanping
     *
     */
    private static class Feature {

        /**
         * The State transition matrix
         */
        private Double[][] transfer;

        /**
         * The observation sequence transition matrix
         */
        private Double[] status;

        /**
         * The predecessor State
         */
        private TreeMap<Integer, Double> preStatus;

        /**
         * The next status
         */
        private TreeMap<Integer, Double> nextStatus;

        /**
         * Total count.
         */
        private int cnt;

        ... ...

    }

     上面代碼中需要注意兩個事項:

     1. 每一個字都會有這樣一個特征類,可以利用一個哈希表,key存字,value存其特征。

     2. 記錄前后上下文的preStatus ,key是上一個字和當前字狀態的組合,nextStatus,key是下一個字和當前字狀態的組合,例如當前字是“我”,當前字的狀態是B,下一個字可能是“們”,在nextStatus中,key就是“們_B”的哈希值,value均是出現這種情況的概率。

     我相信從語料庫中學習這四個特征,應該不是一件很難的事情,自己根據描述完善代碼即可。

     第四步:開始分詞

     既然特征已經訓練好了,怎么去給一個句子分詞呢?例如用戶輸入“希臘的經濟結構較特殊”,怎么就可以進行分詞了呢?其實很簡單,下面就是數學計算了。

     1. 將“希臘的經濟結構較特殊”變成字符數組。即“希”、“臘”、“的”、“經”、“濟”、“結”、“構”、“較”、“特”、“殊”。

     2. 取出每一個字對應特征(第三步產生的內容)。

     現在每一個字的特征以及取出來了,后面怎么辦呢?我們先分析下,我們其實就是在給每一個字確定它是B、M、E、S四個狀態中的哪一種,因此可以繪制一個矩陣。

     條件隨機場分詞3

     到這里,既然是矩陣,而且是求矩陣里面的一個路徑,那么很容易想到維特比算法。到這里,我們只需要計算出“希”字在B、M、E、S的狀態值,后面就游刃而解。

     我們設定矩陣中的值為S, S[字][當前狀態]=MAX(P[上一個字任何狀態][當前狀態]*S[上一個字][任何一個狀態])+W[前(后)一個字_當前狀態][當前字]+R[當前狀態概率]  (備注:R是特征二,P是特征三,W前是特征四的上文部分,W后是特征四的下文部分)

     例如“臘”字,在為狀態B上的值為:S[臘][B]=MAX(P[B][B]*S[希][B],P[M][B]*S[希][M],P[E][B]*S[希][E],P[S][B]*S[希][S])+W前[希_B][臘]+W后[的_B][臘]+R[B],同理可以計算S[臘][M],S[臘][E],S[臘][S]。

     依次類推,可以計算出后面其它字的情況。由於“希”字出現在首字,不存在其它狀態轉移到其狀態的概率,因此,S[希][B]=W前[_B][希]+W后[臘_B][希]+R[B],依次計算出“希”字其它值。

     上面過程,希望反復用研究下,研究透后,你會發現很簡單,通過計算會得到如下矩陣:

    條件隨機場分詞4

    看到這里,你似乎已經看到分詞的結果了,在矩陣中所有值的后面,都有一個小括號,里面存放的是路徑,也就是這個值是通過上一個的哪一個值過來的(因為有計算max的過程,就會有路徑選擇),記錄下來之后,以便於路徑回溯。

    當得到這個矩陣之后,我們只需要將“殊”中的最大值取出,即為1.1867對應狀態是End,來自上一字的狀態0,也就是“特”字的Begin,再次查看“特”字來自於上一個字“較”的Single。因此,判別狀態如下

    “希/B 臘/E 的/S 經/B 濟/E 結/B 構/E 較/S 特/B 殊/E”

    翻譯成分詞結果就是“希臘 的 經濟 結構 較 特殊”。

    完成的實現分詞過程,如果你對此項有點模糊,建議看下維特比算法。

    寫到最后,我也要感謝您能夠看到最后,這是比較簡單的一種利用條件隨機場進行分詞的方式,復雜的,可以在這個基礎上進行優化升級。

    誠摯的謝意!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM