1. 程式人生 > >【中文分詞系列】 8 更好的新詞發現演算法

【中文分詞系列】 8 更好的新詞發現演算法

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

如果依次閱讀該系列文章的讀者,就會發現這個系列共提供了兩種從0到1的無監督分詞方案,第一種就是《【中文分詞系列】 2. 基於切分的新詞發現》,利用相鄰字凝固度(互資訊)來做構建詞庫(有了詞庫,就可以用詞典法分詞);另外一種是

《【中文分詞系列】 5. 基於語言模型的無監督分詞》,後者基本上可以說是提供了一種完整的獨立於其它文獻的無監督分詞方法。

但總的來看,總感覺前面一種很快很爽,卻又顯得粗糙;後面一種很好很強大,卻又顯得太過複雜(viterbi是瓶頸之一)。有沒有可能在兩者之間折中一下?這就導致了本文的結果,達到了速度與效果的平衡。至於為什麼說“更好”?因為筆者研究詞庫構建也有一段時間了,以往構建的詞庫總不能讓人(讓自己)滿意,生成的詞庫一眼看上去,都能夠掃到不少不合理的地方,真的要用得需要經過較多的人工篩選。而這一次,一次性生成的詞庫,一眼掃過去,不合理的地方少了很多,如果不細看,可能就發現不了了。

I. 分詞的目的

分詞一般作為文字挖掘的第一步,彷彿是很自然的,但事實上也應該問個為什麼:為什麼要分詞?人本來就是按照字來書寫和理解的呀?

當模型的記憶和擬合能力足夠強(或者簡單點,足夠智慧)的時候,我們完全可以不用分詞的,直接基於字的模型就可以做,比如基於字的文字分類、問答系統等,早已有人在研究。但是,即便這些模型能夠成功,也會因為模型複雜而導致效率下降,因此,很多時候(尤其是生產環境中),我們會尋求更簡單、更高效的方案。

什麼方案最高效?以文字分類為例,估計最簡單高效的方案就是“樸素貝葉斯分類器”了,類似的,比較現代的是FastText,它可以看作是“樸素貝葉斯”的“神經網路版”。要注意,樸素貝葉斯基於一個樸素的假設:特徵之間相互獨立。這個假設越成立,樸素貝葉斯的效果就越好。然而,對於文字來說,顯然上下文緊密聯絡,這個假設還成立嗎?

注意到,當特徵之間明顯不獨立的時候,可以考慮將特徵組合之後,使得特徵之間的相關性減弱,再用樸素貝葉斯。比如,對於文字,如果以字為特徵,則樸素假設顯然不成立,如“我喜歡數學”中的“喜”和“歡”、“數”和“學”都明顯相關,這時候我們可以考慮將特徵進行組合,得到“我/喜歡/數學”,這樣三個片段之間的相關性就沒有那麼強了,因此可以考慮用上述結果。可以發現,這個過程很像分詞,或者反過來說,分詞的主要目的之一,就是將句子分為若干個相關性比較弱的部分,便於進一步處理。從這個角度來看,分的可能不一定是“詞”,也可能是短語、常用搭配等。

說白了,分詞就是為了削弱相關性,降低對詞序的依賴,這一點,哪怕在深度學習模型中,都是相當重要的。有些模型,不分詞但是用CNN,也就是把若干個字組合作為特徵來看,這也是通過字的組合來減弱特徵間的相關性的體現。

II. 演算法大意

既然分詞是為了削弱相關性,那麼我們分詞,就是在相關性弱的地方切斷了。文章《【中文分詞系列】 2. 基於切分的新詞發現》其實就是這個意思,只是那裡認為,文字的相關性僅由相鄰兩字(2grams)來決定,這在很多時候都是不合理的,比如“林心如”中的“心如”、“共和國”中的“和國”,凝固度(相關性)都不是很強,容易錯切。因此,本文就是在前文的基礎上改進,那裡只考慮了相鄰字的凝固度,這裡同時考慮多字的內部的凝固度(ngrams),比如,定義三字的字串內部凝固度為:


這個定義其實也就是說,要列舉所有可能的切法,因為一個詞應該是處處都很“結實”的,4字或以上的字串凝固度類似定義。一般地,我們只需要考慮到4字(4grams)就好(但是注意,我們依舊是可以切出4字以上的詞來的)。

考慮了多字後,我們可以設定比較高的凝固度閾值,同時防止諸如“共和國”之類的詞不會被切錯,因為考慮三字凝固度,“共和國”就顯得相當結實了,所以,這一步就是“寧放過,勿切錯”的原則。

但是,“各項”和“專案”這兩個詞,它們的內部凝固度都很大,因為前面一步是“寧放過,勿切錯”,因此這樣會導致“各專案”也成詞,類似的例子還有“支撐著”、“球隊員”、“珠海港”等很多例子。但這些案例在3grams中來看,凝固度是很低的,所以,我們要有一個“回溯”的過程,在前述步驟得到詞表後,再過濾一遍詞表,過濾的規則就是,如果裡邊的n字詞,不在原來的高凝固度的ngrams中,那麼就得“出局”。

所以,考慮ngrams的好處就是,可以較大的互資訊閾值情況下,不錯切詞,同時又排除模凌兩可的詞。就比如“共和國”,三字互資訊很強,兩字就很弱了(主要還是因為“和國”不夠結實),但是又能保證像“的情況”這種不會被切出來,因為閾值大一點,“的情”和“的情況”都不結實了。

III. 詳細的演算法

完整的演算法步驟如下:

第一步,統計:選取某個固定的,統計2grams、3grams、…、ngrams,計算它們的內部凝固度,只保留高於某個閾值的片段,構成一個集合;這一步,可以為2grams、3grams、…、ngrams設定不同的閾值,不一定要相同,因為字數越大,一般來說統計就越不充分,越有可能偏高,所以字數越大,閾值要越高;

第二步,切分:用上述grams對語料進行切分,並統計頻率。切分的規則是,只有一個片段出現在前一步得到的集合中,這個片段就不切分,比如“各專案”,只要“各項”和“專案”都在中,這時候就算“各專案”不在中,那麼“各專案”還是不切分,保留下來;

第三步,回溯:經過第二步,“各專案”會被切出來(因為第二步保證寧放過,不切錯)。回溯就是檢查,如果它是一個小於等於字的詞,那麼檢測它在不在中,不在就出局;如果它是一個大於字的詞,那個檢測它每個字片段是不是在中,只要有一個片段不在,就出局。還是以“各專案”為例,回溯就是看看,“各專案”在不在3gram中,不在的話,就得出局。

IV. 程式碼實現

下面給出一個參考的程式碼實現。首先,為了節約記憶體,寫一個迭代器來逐篇輸出文章: