Python自然語言處理入門

Ree Ray發表於2016-05-14

本文從概念和實際操作量方面,從零開始,介紹在Python中進行自然語言處理。文章較長,且是PDF格式。

作者案:本文是我最初發表在《ACM Crossroads》Volume 13,Issue 4 上的完整修訂版。之所以修訂是因為 Natural Language Toolkit(NLTK)改動較大。修訂版程式碼相容至最新版 NLTK(2013 年 9 月更新至 2.0.4 版)。儘管本文的程式碼一律經過測試,仍有可能出現一兩個問題。如果你發現了問題,請向作者反映。如果你非用 0.7 版不可的話,請參考 這裡

1 緣起

本文試著向讀者們介紹自然語言處理(Natural Language Processing)這一領域,通常簡稱為 NLP。然而,不同於一般只是描述 NLP 重要概念的文章,本文還藉助 Python 來形象地說明。對於不熟悉 Python 的讀者們,本文也提供了部分參考資料教你如何進行 Python 程式設計。

2 相關介紹

2.1 自然語言處理

自然語言處理廣納了眾多技術,對自然或人類語言進行自動生成,處理與分析。雖然大部分 NLP 技術繼承自語言學和人工智慧,但同樣受到諸如機器學習,計算統計學和認知科學這些相對新興的學科影響。

在展示 NLP 技術的例子前,有必要介紹些非常基礎的術語。請注意:為了讓文章通俗易懂,這些定義在語言上就不一定考究。

  • 詞例(Token):對輸入文字做任何實際處理前,都需要將其分割成諸如詞、標點符號、數字或純字母數字(alphanumerics)等語言單元(linguistic units)。這些單元被稱為詞例。
  • 句子:由有序的詞例序列組成。
  • 詞例還原(Tokenization):將句子還原成所組成的詞例。以分割型語言(segmented languages)英語為例,空格的存在使詞例還原變得相對容易同時也索然無味。然而,對於漢語和阿拉伯語,因為沒有清晰的邊界,這項工作就稍顯困難。另外,在某些非分割型語言(non-segmented languages)中,幾乎所有的字元(characters)都能以單字(one-character)存在,但同樣也可以組合在一起形成多字(multi-characterwords)形式。
  • 語料庫:通常是由豐富句子組成的海量文字。
  • 詞性標籤(Part-of-speech (POS) Tag):任一單詞都能被歸入到至少一類詞彙集(set of lexical)或詞性條目(part-of-speech categories)中,例如:名詞、動詞、形容詞和冠詞等。詞性標籤用符號來代表一種詞彙條目——NN(名詞)、VB(動詞)、JJ(形容詞)和 AT(冠詞)。Brown Corpus 是最悠久,也是最常用的標註集之一。詳情且聽下回分解。
  • 剖析樹(Parse Tree):利用形式語法(formal grammar)的定義,可以用樹狀圖來表示給定句子的句法(syntactic)結構。

認識了基本的術語,下面讓我們瞭解 NLP 常見的任務:

  • 詞性標註(POS Tagging):給定一個句子和組詞性標籤,常見的語言處理就是對句子中的每個詞進行標註。舉個例子,The ball is red,詞性標註後將變成 The/AT ball/NN is/VB red/JJ。最先進的詞性標註器[9]準確率高達 96%。文字的詞性標註對於更復雜的 NLP 問題,例如我們後面會討論到的句法分析(parsing)機器翻譯(machine translation)非常必要。
  • 計算形態學(Computational Morphology):大量建立在“語素”(morphemes/stems)基礎上的片語成了自然語言,語素雖然是最小的語言單元,卻富含意義。計算形態學所關心的是用計算機發掘和分析詞的內部結構。
  • 句法分析(Parsing):在語法分析的問題中,句法分析器(parser)將給定句子構造成剖析樹。為了分析語法,某些分析器假定一系列語法規則存在,但目前的解析器已經足夠機智地藉助複雜的統計模型[1]直接推斷分析樹。多數分析器能夠在監督式設定(supervised setting)下操作並且句子已經被詞性標註過了。統計句法分析是自然語言處理中非常活躍的研究領域。
  • 機器翻譯(Machine Translation(MT)):機器翻譯的目的是讓計算機在沒有人工干預的情況下,將給定某種語言的文字流暢地翻譯成另一種語言文字。這是自然語言處理中最艱鉅的任務之一,這些年來已經用許多不同的方式解決。幾乎所有的機器翻譯方法都依賴了詞性標註和句法分析作為預處理。

2.2 Python

Python 是一種動態型別(dynamically-typed),物件導向的解釋式(interpreted)程式語言。雖然它的主要優勢在於允許程式設計人員快速開發專案,但是大量的標準庫使它依然能適應大規模產品級工程專案。Python 的學習曲線非常陡峭並且有許多優秀的線上學習資源[11]。

2.3 自然語言工具集(Natural Language Toolkit)

儘管 Python 絕大部分的功能能夠解決簡單的 NLP 任務,但不足以處理標準的自然語言處理任務。這就是 NLTK (自然語言處理工具集)誕生的原因。NLTK 整合了模組和語料,以開源許可釋出,允許學生對自然語言處理研究學習和生產研究。使用 NLTK 最大的優勢是整合化(entirely self-contained),不僅提供了方便的函式和封裝用於建立常見自然語言處理任務塊,而且提供原始和預處理的標準語料庫版本應用在自然語言處理的文獻和課程中。

3 使用 NLTK

NLTK 官網提供了很棒的說明檔案和教程進行學習指導[13]。單純複述那些作者們的文字對於他們和本文都不公平。因此我會通過處理四個難度係數依次上升的 NLP 任務來介紹 NLTK。這些任務都來自於 NLTK 教程中沒有給出答案的練習或者變化過。所以每個任務的解決辦法和分析都是本文原創的。

3.1 NLTK 語料庫

正如前文所說,NLTK 囊括數個在 NLP 研究圈裡廣泛使用的實用語料庫。在本節中,我們來看看三個下文會用到的語料庫:

  • 布朗語料庫(Brown Corpus):Brown Corpus of Standard American English 被認為是第一個可以在計算語言學處理[6]中使用的通用英語語料庫。它包含了一百萬字 1961 年出版的美語文字。它代表了通用英語的樣本,取樣自小說,新聞和宗教文字。隨後,在大量的人工標註後,誕生了詞性標註過的版本。
  • 古登堡語料庫(Gutenberg Corpus):古登堡語料庫從最大的線上免費電子書[5]平臺 古登堡計劃(Gutenberg Project) 中選擇了 14 個文字,整個語料庫包含了一百七十萬字。
  • Stopwords Corpus:除了常規的文字文字,另一類諸如介詞,補語,限定詞等含有重要的語法功能,自身卻沒有什麼含義的詞被稱為停用詞(stop words)。NLTK 所收集的停用詞語料庫(Stopwords Corpus)包含了 來自 11 種不同語言(包括英語)的 2400 個停用詞。

3.2 NLTK 命名約定

在開始利用 NLTK 處理我們的任務以前,我們先來熟悉一下它的命名約定(naming conventions)。最頂層的包(package)是 nltk,我們通過使用完全限定(fully qualified)的加點名稱例如:nltk.corpus and nltk.utilities 來引用它的內建模組。任何模組都能利用 Python 的標準結構 from . . . import . . . 來匯入頂層的名稱空間。

3.3 任務 1 : 探索語料庫

上文提到,NLTK 含有多個 NLP 語料庫。我們把這個任務制定為探索其中某個語料庫。

任務:用 NLTK 的 corpus 模組讀取包含在古登堡語料庫的 austen-persuasion.txt,回答以下問題:

  • 這個語料庫一共有多少字?
  • 這個語料庫有多少個唯一單詞(unique words)?
  • 前 10 個頻率最高的詞出現了幾次?

利用 corpus 模組可以探索內建的語料庫,而且 NLTK 還提供了包含多個好用的類和函式在概率模組中,可以用來計算任務中的概率分佈。其中一個是 FreqDist,它可以跟蹤分佈中的取樣頻率(sample frequencies)。清單1 演示瞭如何使用這兩個模組來處理第一個任務。

清單 1: NLTK 內建語料庫的探索.

解答:簡奧斯丁的小說 Persuasion 總共包含 98171 字和 6141 個唯一單詞。此外,最常見的詞例是逗號,接著是單詞the。事實上,這個任務最後一部分是最有趣的經驗觀察之一,完美說明了單詞的出現現象。如果你對海量的語料庫進行統計,將每個單詞的出現次數和單詞出現的頻率由高到低記錄在表中,我們可以直觀地發現列表中詞頻和詞序的關係。事實上,齊普夫(Zipf)證明了這個關係可以表達為數學表示式,例如:對於任意給定單詞,$fr$ = $k$, $f$ 是詞頻,$r$ 是詞的排列,或者是在排序後列表中的詞序,而 $k$ 則是一個常數。所以,舉個例子,第五高頻的詞應該比第十高頻的詞的出現次數要多兩倍。在 NLP 文獻中,以上的關係通常被稱為“齊普夫定律(Zipf’s Law)”。

即使由齊普夫定律描述的數學關係不一定完全準確,但它依然對於人類語言中單詞分佈的刻畫很有用——詞序小的詞很常出現,而稍微詞序大一點的則較為少出現,詞序非常大的詞則幾乎沒有怎麼出現。任務 1 最後一部分使用 NLTK 非常容易通過圖形進行視覺化,如 清單 1a 所示。相關的 log-log 關係,如圖 1,可以很清晰地發現我們語料庫中對應的擴充套件關係。

 

清單 1a: 使用 NLTK 對齊普夫定律進行作圖

Zipf

圖 1: 齊普夫定律在古登堡語料庫中適用嗎?

3.4 任務 2:預測單詞

現在我們已經探索過語料庫了,讓我們定義一個任務,能夠用上之前探索的結果。

任務:訓練和建立一個單詞預測器,例如:給定一個訓練過語料庫,寫一個能夠預測給定單詞的一下個單詞的程式。使用這個預測器隨機生成一個 20 個詞的句子。

要建立單詞預測器,我們首先要在訓練過的語料庫中計算兩個詞的順序分佈,例如,我們需要累加給定單詞接下來這個單詞的出現次數。一旦我們計算出了分佈,我們就可以通過輸入一個單詞,得到它在語料庫中所有可能出現的下一個單詞列表,並且可以從列表中隨機輸出一個單詞。為了隨機生成一個 20 個單詞的句子,我只需要給定一個初始單詞,利用預測器來預測下一個單詞,然後重複操作指導直到句子滿 20 個詞。清單 2 描述了怎麼利用 NLTK 提供的模組來簡單實現。我們利用簡奧斯丁的 Persuasion 作為訓練語料庫。

清單 2:利用 NLTK 預測單詞

解答:輸出的 20 個單詞的句子當然不合語法。但就詞的角度兩兩來看,是合語法的,因為用以估計條件分佈概率(conditional frequency distribution)的訓練語料庫是合乎語法的,而我們正是使用了這個條件分佈概率。注意在本任務中,我們使用前一個詞作為預測器的上下文提示。顯然也可以使用前兩個,甚至前三個詞。

3.5 Task 3: 探索詞性標籤

NLTK 結合了一系列優秀的模組允許我們訓練和構建相對複雜的詞性標註器。然而,對於這次的任務,我們只限於對 NTLK 內建的已經標註過的語料庫進行簡單分析。

任務:對內建的布朗語料庫分詞(Tokenize)並建立一個或多個適合的資料結構能讓我們回答以下問題:

  • 最高頻的詞性標籤是什麼?
  • 哪個詞被不同的詞性標籤標註最多
  • 男性代詞對於女性代詞的出現頻率比率如何?
  • 多少個詞是有歧義(ambiguous)的?也就是至少有兩個詞性標籤?

對於這個任務,一定要注意 NTLK 內建了兩個版本的布朗語料庫:第一個我們已經在前兩個任務中使用了,是原始的版本,第二個是被標註過的版本,亦即是每個句子的每個詞例都被正確地詞性標註過了。這一版的每個句子儲存在元素為二元元組的列表中,形如: (token,tag)。例如標註過的語料庫中的一個句子 the ball is green,在 NLTK 會被表示為 [(’the’,’at’), (’ball’,’nn’), (’is’,’vbz’), (’green’,’jj’)]。

前面已經解釋過了,布朗語料庫包含 15 個不同的部分,用單詞 “a”“r” 來表示。每個部分代表不同的文字型別,這樣分是很有必要的,但這不在本文討論範圍內。有了這個資訊,我們必須要構建資料結構來分析這個標註過的語料庫。思考我們需要解決的問題,我們要運用文字中的詞例來發現詞性標準的頻率分佈和詞性標籤的條件頻率分佈。注意 NLTK 同時也允許我們直接從頂層名稱空間匯入 FreqDistConditionalFreqDist 類。清單 3 演示了怎樣在 NLTK 使用。

 

清單 3: 藉助 NLTK 分析標註過的語料庫

解答:在布朗語料庫中最高頻的詞性標籤理所當然是名詞(NN)。含有最多詞性標籤的是詞是 that。語料庫中的男性代詞使用率差不多是女性代詞的三倍。最後,語料庫中有 8700 多的詞仍有歧義——這個數字可以看出詞性標註任務的困難程度。

3.6 任務 4: 單詞聯想(Word Association)

自由單詞聯想是神經語言學(Psycholinguistics)常見的任務,尤其是在詞彙檢索(lexical retrieval)的語境下——對於人類受試者(human subjects)而言,在單詞聯想上,更傾向於選擇有高度聯想性詞,而非完全無關的詞。這說明單詞聯想的處理是相當直接的——受試者在聽到一個特殊的詞時要馬上從心裡泛起另一個詞。

任務:利用大規模詞性標註過的語料庫來實現自由單詞聯想。忽略功能詞(function words),假設聯想詞都是名詞。

對於這個任務而言,需要用到“詞共現”(word co-occurrences)這一概念,例如:統計彼此間最接近的單詞出現次數,然後藉此估算出聯想度。對於句子中的每個詞例,我們將其觀察規定範圍內接下來所有的詞並且利用條件頻率分佈統計它們在該語境的出現率。清單 4 演示了我們怎麼用 Python 和 NLTK 對規定在 5 個單詞的範圍內的詞性標註過的布朗語料庫進行處理。

 

Listing 4: 利用 NLTK 實現單詞聯想

解答:我們構建的“單詞聯想器(word associator)”效果似乎出乎意料得好,尤其是在這麼小的工作量下(事實上,在大眾心理學的的語境下,我們的聯想器似乎具備人類的特性,儘管是消極和悲觀的)。我們的任務結果明確指出了通用語料庫語言學的有效性。作為進一步的練習,聯想器藉助句法分析過的語料庫和基於資訊理論的聯想測試能夠很容易進行成熟的擴充[3]。

4 討論

雖然本文使用了 Python 和 NLTK 作為基礎 NLP 的介紹,但請注意,在 NLTK 之外還有另外的 NLP 框架活躍於學術界和工業界。其中比較流行的是 GATE(General Architecture for Text Engineering),由 University of Sheffield[4] 的 NLP 研究小組開發。使用 Java 編寫的視窗環境,基礎架構描述了語言處理部件彼此間的聯絡。GATE 提供免費下載,主要應用於文字挖掘(text mining)和資訊抽取(information extraction)。

每種程式語言和框架都各有優劣。就本文而言,我們選擇 Python 是因為與其他語言相比,它的優勢在於:(a)可讀性高(b)面相物件的範例(object-oriented paradigm)易於入門(c)易於擴充套件(d)強大的解碼支援(e)強大的標準庫。而且特別穩健,高效,這些都已經在複雜和大規模的 NLP 專案中得到了驗證,例如最新的機器翻譯解碼器[2]。

5 結論

自然語言處理是非常熱門的研究領域因此每年吸引了非常多研究生。它集合了多個學科諸如語言學,心理學,計算科學和數學的優勢來研究人類語言。另外選擇 NLP 作為研究生生涯更重要的原因是大量有意思的難題都沒有固定的解決辦法。舉個例子,機器翻譯初始問題(original problem)的存在推動了該領域的發展,即使經過二十年誘人而又活躍的研究以後,這個難題依舊尚待解決。還有另外幾個前沿的 NLP 問題目前已經有大量的研究工作,其中一些列舉如下:

  • 基於句法的機器翻譯:從過去的數十年到現在,絕大部分的機器翻譯都聚焦在使用統計方法通過大量語料庫來學習詞和短語的翻譯。然而,越來越多的研究者開始在研究中加入句法[10]。
  • 多文字摘要:目前大量工作都是利用計算機從相近的文件集合[8]中自動生成高度相關的摘要。這個任務被視為比單文字的摘要困難,因為多文字中冗餘資訊更多。
  • 計算句法分析:雖然使用概率模型自動生成給定文字的句法結構由來已久,但進步空間還很大。最大的挑戰是準確的分析,當英語拿來和中文[7]、阿拉伯語比較的時候,語言特性差異很大。

Python 和 NLTK 使每個程式設計人員不需要花費大量時間在獲取資源上,直接可以接觸 NLP 任務。文字意在給任何對學習 NLP 感興趣的人提供解決這些簡單的任務例子和參考。

6 作者簡介

Nitin Madnani 是 Educational Testing Service(ETS)研究科學家。他此前是 University of Maryland, College Park 電腦科學系的博士生和 Institute for Advanced Computer Studies 助理研究員。他的研究方向是統計自然語言處理,尤其是機器翻譯和文字摘要。不論任務大小,他始終堅信:Python大法好。

參考文獻

[1]: Dan Bikel. 2004. On the Parameter Space of Generative Lexicalized Statistical Parsing Models. Ph.D. Thesis. http://www.cis.upenn.edu/~dbikel/papers/thesis.pdf

[2]: David Chiang. 2005. A hierarchical phrase-based model for statistical machine translation. Proceedings of ACL.

[3]: Kenneth W. Church and Patrick Hanks. 1990. Word association norms, mutual information, and lexicography. Computational Linguistics. 16(1).

[4:] H. Cunningham, D. Maynard, K. Bontcheva. and V. Tablan. 2002. GATE: A Framework and Graphical Development Environment for Robust NLP Tools and Applications. Proceedings of the 40th Anniversary Meeting of the Association for Computational Linguistics. 15

[5]: Michael Hart and Gregory Newby. Project Gutenberg. Proceedings of the 40th Anniversary Meeting of the Association for Computational Linguistics. http://www.gutenberg.org/wiki/Main_Page

[6]: H. Kucera and W. N. Francis. 1967. Computational Analysis of PresentDay American English. Brown University Press, Providence, RI.

[7]: Roger Levy and Christoper D. Manning. 2003. Is it harder to parse Chinese, or the Chinese Treebank ? Proceedings of ACL.

[8]: Dragomir R. Radev and Kathy McKeown. 1999. Generating natural language summaries from multiple on-line sources. Computational Linguistics. 24:469-500.

[9]: Adwait Ratnaparkhi 1996. A Maximum Entropy Part-Of-Speech Tagger. Proceedings of Empirical Methods on Natural Language Processing.

[10]: Dekai Wu and David Chiang. 2007. Syntax and Structure in Statistical Translation. Workshop at HLT-NAACL.

[11]: The Official Python Tutorial. http://docs.python.org/tut/tut.html

[12]: Natural Language Toolkit. http://nltk.sourceforge.net

[13]: NLTK Tutorial. http://nltk.sourceforge.net/index.php/Book

打賞支援我翻譯更多好文章,謝謝!

打賞譯者

打賞支援我翻譯更多好文章,謝謝!

任選一種支付方式

Python自然語言處理入門 Python自然語言處理入門

相關文章