1. 程式人生 > >【演算法記事本#NLP-1】最大匹配演算法分詞

【演算法記事本#NLP-1】最大匹配演算法分詞

> **本文地址**: # \#NLP-1 最大匹配演算法(MM) **最大匹配演算法**(Maximum Matching)被用於對一個**文段**進行**詞語劃分**(Word Segmentation)。 > ## 注意 > 這是**詞元化(Tokenization)演算法** > 此方法**不適用於**無分隔符的字母語言(e.g.:**德語**、使用假名替代漢字的**日語**、被取消分詞符的**英文**等) > 但是對**漢語**這類無詞間分隔符但不依賴字母的語言**效果拔群** ## 輸入輸出 ```mermaid graph LR input1(文段P) input2(單詞表W) processor(MM) output(詞元表T) input1--輸入-->
processor input2--輸入-->processor processor--輸出-->output ``` ## 演算法內容 > ## 人話版本(自然描述) > **輸入**:文段$\small P$,單詞表$\small W$ > **過程**:對於給定的$\small P$和$\small W$: > 1. 令指標$\small i$從$\small P$的起點開始 > 2. 每當找到**最長匹配**於$\small i$引領文段的單詞$\small w$,則將$\small w$加入詞元分析表$\small T$(一個順序表結構)中 > 3. $\small i$向後移動$\small w$長度個位置 >
4. 回到2,直至$\small i$無法向後移動為止 > > **輸出**:詞元分析表$\small T$ ## 說明 ### 最長匹配?? 這個概念用定義去描述其實很不容易理解,這裡直接上例子,比如,有一個字串 ```text The quick brown fox jumps over a lazy dog ``` 現在給出這麼幾個字串:`Th`、`The`、`The slow`、`The quick brown fox jumps over a lazy dog and a little duck`、`quick brown` > 注意,最長匹配的前提是**能匹配得上**,此外還要求是**端點匹配** 先看`Th`,很明顯,儘管`Th`不能完美的匹配上原有字串,但卻是原字串的**子串**(Substring),也就是說它能夠完美的和原字串的區域性相匹配,而且是**從起始位置相匹配**,可以**暫時認為**是原字串的**最長匹配**。 再看`The`,和`Th`一樣,其整體能夠匹配上原字串的部分,而且也是從起始位置匹配,因此也可能是最長匹配,這樣一來`Th`和`The`都能匹配上原字串,但是 >
一個字串在一個給定的字串集合中**只能找到一個**最長匹配,而且是**儘可能長**的那個 考慮到`The`比`Th`長,因此`The`替掉了`Th`成為了目前的**最長匹配** 接下來看看`The slow`,截止到`The `都能匹配到原字串上,但接下來的`s`卻**無法匹配原字串**,儘管匹配部分的長度比`The`還長,但很遺憾,`The slow`只能認為是**不匹配**。 `The quick brown fox jumps over a lazy dog and a little duck`也是同理,別看它甚至是原字串的延長串(也就是原字串是它的子串),但後面多出來的部分匹配不回去,所以也只能認為是**不匹配**。 > 原字串是大爺!! 最後再看看`quick brown`,當然這也是原字串的子串,而且匹配長度為11,甚至比`The`的匹配性還強,但是也很遺憾,這並**不是從起點**匹配的,所以這個**無法認為匹配** 於是我們得到了結論: > 在上述給出的5個字串中,最長匹配為`The` 當然,這都是**目前的最長匹配**,如果我們繼續給出`The quick`、`The quick brown`、……這個結果還是會跟著變化的,因為: > 理論上,從**所有字串構成的全集**尋找某一字串的最長匹配,其結果只能是該字串本身 ### 為什麼對漢語效果拔群?? 這裡先說對英語吧…… 因為是做詞元化工作,所以這裡**暫時無視英語中的空格分隔符**。 ```text We are talking about weather. ↓ 移除所有分詞符 Wearetalkingaboutweather. ``` 當然,我們要對下面的內容做分詞,按說分詞工作做完後其分割結果應該和移除之前是一樣的:`We|are|talking|about|weather|.` 但如果採用MM演算法使用一個標準詞庫進行匹配,就會是下面這樣: > 首先從`W`開始,從詞庫中尋找從`W`開始能夠最長匹配的字串,然後非常巧,我們在詞典中找到了……`Wear`!! > …… 於是,我們先不管後面能不能分出來,反正分完肯定是這樣子:`Wear|...|...`。 很明顯這種分法是不行的。 這裡面的原因就在於:英語一共就26個字母,隨便找若干個字母湊成一個單詞的概率還是很大的,特別是移除分隔符後出現大量子音字母+若干母音字母的情況。 而且,英語中詞彙的長度方差很大,短的只有一個字母,長的可以10多個,極端情況下也有40多個的甚至更多,很多短單詞會成為一些長單詞的子串(`we`之於`wear`等),而移除分隔符後兩個原本獨立的子串被拼合成一個更長的單詞也不是什麼新鮮事。 一種極端情況: ```mermaid graph LR origin("Hear the voice") obfuscated("Hearthevoice") mm("Heart|he|voice") origin--移除分隔符-->obfuscated obfuscated--MM演算法分割-->mm ``` 但是漢語就不一樣了,就以GB2312裡面的6700多個漢字想隨便挑出來幾個字就湊巧拼出一個詞語還是很困難的,而且詞語長度的方差很低,不考慮詩句和歇後語的話,常用的詞語和成語絕大多數為2~4個字,較長一些的8個字(比較少),這種情況下即使沒有分隔符,兩個獨立的詞語能夠被混淆成一個的機率還是比較小的,比如: ```text 一隻穿雲箭,千軍萬馬來相見 一隻|穿雲|箭|,|千軍萬馬|來|相見 ``` 基本上分割的完全正確,而且即使把標點符號都去掉,也不太影響其分割的結果,斯坦福大學也給出了這樣的評價: > Doesn’t generally work in English! > But works astonishingly well in Chinese! 不過其實說到底,這種演算法**比較依賴於詞典**(事實上很多詞元化演算法都挺依賴詞典),如果詞典編寫的不夠好,那麼即使是漢語其詞元化的質量也不盡如人意(特別是漢語需要足夠完善的詞彙庫,其工作量是相當龐大