1. 程式人生 > 其它 >自然語言處理指南(第1部分)

自然語言處理指南(第1部分)

自然語言處理(NLP)包含一系列技術,用以實現諸多不同的目標。下表中列出瞭解決某些特定問題對應的技術。

你想要

你要看

將類似的詞分組以搜尋

詞幹提取;分詞;文件分析

查詢具有相似含義的詞語以搜尋

潛在語義分析

生成名稱

詞彙拆分

估計閱讀文字需要多長時間

閱讀時間

估計一段文字閱讀的難度

文字可讀性

識別文字的語言

語言識別

生成文字摘要

SumBasic(基於詞);基於圖的演算法:TextRank(基於關係);潛在語義分析(基於語義)

查詢類似檔案

潛在語義分析

識別文字中的實體(即城市,人物)

分檔分析

推測文字表達的態度

文件分析

翻譯一段文字

文件分析

我們將按一般意義上的“分析文件”和“提取文件意義”來討論文件分析而非句法或語法分析,因為二者英文均為 parsing ——譯者注)。 因此,我們會涉及實際的自然語言句法分析,但把更多的時間花在其他技術上。就程式語言理解而言,語法分析方為可行之道,不過也有某些特定的自然語言可供選擇。換言之,我們討論的大都是“你將使用什麼技術”而不是“進行句法分析以完成目標”。

例如,如果你想在一個程式語言檔案中找到所有的for語句,你能通過語法分析計算fors 的個數;而在自然語言檔案種,你可能會使用類似於詞幹提取的技術來找到所有提到的“貓”

這很重要,因為自然語言句法分析背後的理論可能與程式語言語法分析背後的理論是一致的; 然而,其實際操作又是非常不同的。事實上,你不會為自然語言構建一個語法分析器(Parser)

——也就是說,除非你在使用人工智慧或是一個研究人員,甚至就算在這種情況下,你也很少使用語法分析器。正相反,你會找到一個演算法,作為文件的簡化模型,只用以解決你的特定問題。

總之,你是尋找一些技巧使你不必真的去解析一種自然語言。這就是為什麼在電腦科學領域,我們通常稱“自然語言處理”而非“自然語言解析”。

需要資料的演算法

我們將瞭解每個問題的具體解決方案。請注意,這些具體的解決方案本身可能相當複雜。他們越高階,就越不依賴於簡單的演算法。通常情況下,他們需要一個該語言的龐大資料庫。而這樣做的合乎邏輯的結果是,該工具很難移植於另一種語言。或者說,這個工具具有一定的可移植性,但是建立資料庫需要大量的投入。就比如,你很可能找到一個可用的用以建立英文文字摘要的工具,但不能建立義大利文的摘要。

因此,在這一系列指南中,我們主要關注英文工具。儘管我們會提到這些工具是否適用於其他語言,但你不需要知道語言之間的理論差異,例如性、數、格的數量。不要,你要知道,一種語言與英語差異越大,應用這些技術或工具就越難。

例如,你不太能找到能夠與中文(或者說“中文寫作系統”)配合的工具。這些語言不一定是程式設計上難以理解的,但是對它們的研究可能會比較少,或者分析方法可能與英語所採用的完全不同。

本指南的結構

我們按要完成的任務組織文章結構 ——這意味著工具及其解釋按照它們所適用的任務進行分組。例如,有一節是關於度量文字某種屬性(比如它的難度)的。一般來說,它們按照難度從小到大的順序排列 ——給單詞分類比給文件分類要更加容易。始於簡單的資訊檢索技術,終於嚴格意義上的自然語言處理領域。

我們認為這種提供所需資訊的方法最為有效:如果你需要做某某事,我們直接展示你能夠使用的方法和工具。

詞類分類

“詞類分類”這種表述包括將詞彙分組的技術和庫。

相似詞彙分組

我們將介紹兩種以資訊檢索為目的相似詞彙分組方法。總的來說,這些方法用以從文件池中找到包含我們關心詞彙的文件的方法。這是很有用的,因為如果使用者搜尋包含“朋友(friend)”這個詞的文件,他們很可能也對包含“友誼(friendship)”“交友(friended)”“好友(friends)”的文件感興趣。

所以說白了,在本節中,我們不會討論根據語義來將詞彙分組的方法,例如識別所有寵物或所有英國城鎮名。

這兩種方法分別是“詞幹提取”“詞彙拆分”。前者的演算法依賴語言,而後者不是。我們將分兩部分來分析。

詞幹提取

詞幹提取是找到一個詞的詞幹(stem)或者詞根(root)的過程。在這種情況下,詞幹不一定是語言學家所論的形態上的詞根。所以它不是單詞的某種形式,你可能沒法在詞彙表上找到。例如,一個演算法可能由“consoling(安慰)”一詞生成詞幹“consol”,而在一個詞彙表中,你會它的詞根是“console”

詞幹提取的典型應用是將具有相同詞幹的詞的所有例項組合在一起以供在搜尋庫中使用。因此,如果使用者搜尋包含“friend”的文件,他們也會找到“friends”“friended”的文件。

波特詞幹演算法

讓我們來談談一個通過移除字尾以提取詞幹的演算法:有效和廣泛使用的 Porter 詞幹演算法。該演算法最初由Martin Porter為英語設計。對於其他語言(如法語或俄語),也有基於 Porter 的或受其啟發的演算法。你可以在 Snowball 這個網站上找到所有的演算法。Snowball 是一種用來描述詞幹提取演算法的簡單語言,不過這些演算法也有簡單的英文描述。

篇幅所限,本指南無法完整敘述該演算法。但是,它的基礎部分很容易掌握。從根本上說,該演算法將一個單詞分成若干區域,然後如果這些區域完整包含了這些字尾的話,替換或移除某些字尾。例如,Porter 2(即更新版本)演算法指出:

R1 是母音後第一個非母音之後的區域,如果沒有非母音則為單詞結尾。

如果在 R1 區域內找到了“-tional”,則用“-tion”替換之。

舉例:

  1. confrontational的 R1 區域為-frontational
  2. 其 R1 區完全包含了-tional
  3. confrontational變成了confrontation

波特詞幹提取器是純演算法的,這意味著它不依賴於外部資料庫或計算規則(即參照訓練集建立的規則)。這是一個很大的優勢,因為它易於預測和實施。劣勢在於不能處理例外情況,而且已知錯誤難以解決。例如,該演算法對“university(大學)”“universal(通用的)”建立相同的詞幹。

波特詞幹提取器並非完美的——它簡單,有效,且易於實現。對於像英語這樣的語言來說,任何有能力的開發者都可以實現一個詞幹提取器。正因如此,你能找到基於各種著名程式語言的實現,我們在此不一一列出。

在其他語言上的典型問題

大多數與英語接近的語言,如德語甚至羅曼語族,通常都很容易提取詞幹。實際上,演算法本身的設計就很複雜,需要高深的語言學知識。但是,一旦有人花大力氣設計號一個演算法,再去實現演算法就容易了。

在詞幹提取中,兩種型別的語言往往會遇到許多問題。第一種是黏著語。我們不談其語言學意義,其問題就在於黏著語的詞根堆滿了字首和字尾。

特別地,如土耳其語就很容易引起問題,因為它既是一種黏著語,也是一種拼接語,這意味著土耳其語中的一個詞基本上可以代表整個英語句子。這使得設計一個土耳其語詞幹提取演算法十分困難,就算能開發出來也未必有用——因為如果你提取的是土耳其語單詞,那麼每個句子最後只會有一個詞幹,丟失了很多資訊。

第二類問題源於那些詞彙沒有明確定義的語言。中文是沒有字母表的語言的典型,它只有表示概念的符號。所以,詞幹提取對中國人來說沒有意義,就連確定概念的明確界限也很困難。劃分文字間詞彙組成的問題被稱為分詞。在英語中,你可以通過查詢空格或標點符號來找到詞彙間的界限,中文則沒有這樣的東西。

詞彙拆分

另一種進行詞彙分組的方法是將詞彙分割開來。這種方法的核心是把文字分解成字串。這些字元被稱為k-grams( n 元模型),也被稱為n-grams characters ( n 元字元模型)( n-grams 有時也表示以單詞為組,即 n 元單詞模型)。字元序列以滑動的方式構建,在每個步中前進一個字元,以指示字的邊界的特殊符號開始和結束。例如,happy的 3 元模型是:

  • $ha
  • hap
  • app
  • ppy
  • py $

用符號$來表示單詞的開始和結束。

用於搜尋的確切方法超出了本文的範圍。一般而言,你對搜尋項進行上述處理,然後比較輸入的 n 元模型與文件中的某個詞二者的出現次數。通常情況下是選用一個統計係數,如 Jaccard 相似係數,以確定多相似的詞彙要被分在一組(即有多少共同元)。例如,由於相似係數高,你會把“cat”“cats”分組,或者“cat”“catty”

需要注意幾點:n 元模型的順序和拼寫錯誤。n 元模型的順序無關緊要,從理論上說,完全不同的單詞可能碰巧具有相同的 n 元模型。不過在實踐中,這不會發生。這種方法並不精確,這意味著它也可以防止使用者的拼寫錯誤。例如,即使使用者將“locomotive”拼成了“locamotive”,它仍可能顯示正確的結果。那是因為 10個 3 元模型中有 7 個是相匹配的。完全匹配會排在更高的位置,但因為“locamotive”這個詞並不存在,所以它一般沒有其他匹配。

限制和有效性

這種技術的巨大優勢在於,它不僅僅是演算法簡單,而且還適用於所有語言。你不需要為法語建立不同於英語的 n 元模型,製藥以相同的方式拆分這些單詞就好。不過重要的是要注意有效性的細節——你必須選擇正確的大小n以獲得最好的結果。

這個理想數字取決於該種語言中單詞的長度,它應該低於或等於平均單詞長度。不同的語言取值不同,但一般來說,選擇 4 或 5 都能成功。只選擇一種並不能得出最好的結果,儘管這也行得通。

缺點是它看起來非常愚蠢,真的:它太簡單了,它怎麼行得通呢?但實際上它真的可以,就算不比詞幹提取法好,它至少也行得通呀(PDF)。就是這麼無恥地有效,並且還有許多其他用途。我們現在來看一個應用:

生成名稱

一般情況下,生成貌似真實的虛假單詞很困難,而且用處有限。你可以為一種偽造語言生成許多短語,但要太多了。但是,你可以通過程式設計生成逼真的假名字,用於遊戲或任何架空世界建構的需求。

這裡有幾種可行的方法,最簡單的大概是這樣工作的:

  1. 建立一個你想要生成的同類型名字的資料庫(即羅馬名字,太空蜥蜴人的名字等)。
  2. 以 n 元模型處理輸入的名字 (如 Mark 的 3 元模型 -> $ma - mar - ark - rk$)。
  3. 將概率與 n 元模型相關聯:在原始資料庫中出現的頻率越高,其出現在生成名稱中的概率就越高。
  4. 生成新的名字!

這有許多變種。例如,你可以將不同數量的 n 元模型結合起來以滿足特定要求(如所有名稱以 2 元模型開頭,以 4 元模型結尾)。

你也可以僅通過檢查序列以特定順序出現的概率來提高生成名字的可靠性。例如,如果你隨機以“ar”開頭,之後音節更可能是“th”而非“or”。

這種方法並不完美,但通常工作得很不錯。這裡有幾個簡單的示例: langgenVNameGenerator,它們體現了我們提到的方法,同時還有一些別的方法。

結論

第一部分就到此為止了!在第 2 部分中,我們將討論對文件分類。在以後的文章中,我們會討論文件理解,文件分析,情感分析,自然語言處理的庫等等。

敬請關注!