1. 程式人生 > >利用NLTK在Python下進行自然語言處理

利用NLTK在Python下進行自然語言處理

自然語言處理是電腦科學領域與人工智慧領域中的一個重要方向。自然語言工具箱(NLTK,Natural Language Toolkit)是一個基於Python語言的類庫,它也是當前最為流行的自然語言程式設計與開發工具。在進行自然語言處理研究和應用時,恰當利用NLTK中提供的函式可以大幅度地提高效率。本文就將通過一些例項來向讀者介紹NLTK的使用。

開發環境:我所使用的Python版本是最新的3.5.1,NLTK版本是3.2。Python的安裝不在本文的討論範圍內,我們略去不表。你可以從NLTK的官網上http://www.nltk.org/ 獲得最新版本的NLTK。Anyway,使用pip指令來完成NLTK包的下載和安裝無疑是最簡便的方法。

當然,當你完成這一步時,其實還不夠。因為NLTK是由許多許多的包來構成的,此時執行Python,並輸入下面的指令(當然,第一條指令還是要匯入NLTK包)

>>> import nltk
>>> nltk.download()

然後,Python Launcher會彈出下面這個介面,建議你選擇安裝所有的Packages,以免去日後一而再、再而三的進行安裝,也為你的後續開發提供一個穩定的環境。某些包的Status顯示“out of date”,你可以不必理會,它基本不影響你的使用與開發。


既然你已經安裝成功,我們來小試牛刀一下。當然本文涉及的主要任務都是自然語言處理中最常用,最基礎的pre-processing過程,結合機器學習的高階應用我們會在後續文章中再進行介紹。

1、 Sentences Segment(分句)

也就是說我們手頭有一段文字,我們希望把它分成一個一個的句子。此時可以使用NLTK中的 punkt sentence segmenter。來看示例程式碼

>>> sent_tokenizer = nltk.data.load('tokenizers/punkt/english.pickle')
>>> paragraph = "The first time I heard that song was in Hawaii on radio. 
... I was just a kid, and loved it very much! What a fantastic song!"
>>> sentences = sent_tokenizer.tokenize(paragraph)
>>> sentences
['The first time I heard that song was in Hawaii on radio.', 
 'I was just a kid, and loved it very much!', 
 'What a fantastic song!']

由此,我們便把一段話成功分句了。

2、Tokenize sentences (分詞)

接下來我們要把每個句話再切割成逐個單詞。最簡單的方法是使用NLTK 包中的 WordPunct tokenizer。來看示例程式碼

>>> from nltk.tokenize import WordPunctTokenizer
>>> sentence = "Are you old enough to remember Michael Jackson attending 
... the Grammys with Brooke Shields and Webster sat on his lap during the show?"
>>> words = WordPunctTokenizer().tokenize(sentence)
>>> words
['Are', 'you', 'old', 'enough', 'to', 'remember', 'Michael', 'Jackson', 'attending',
 'the', 'Grammys', 'with', 'Brooke', 'Shields', 'and', 'Webster', 'sat', 'on', 'his',
 'lap', 'during', 'the', 'show', '?']

我們的分詞任務仍然完成的很好。除了WordPunct tokenizer之外,NLTK中還提供有另外三個分詞方法,

TreebankWordTokenizer,PunktWordTokenizer和WhitespaceTokenizer,而且他們的用法與WordPunct tokenizer也類似。然而,顯然我們並不滿足於此。對於比較複雜的詞型,WordPunct tokenizer往往並不勝任。此時我們需要藉助正則表示式的強大能力來完成分詞任務,此時我所使用的函式是regexp_tokenize()。來看下面這段話

>>> text = 'That U.S.A. poster-print costs $12.40...'

目前市面上可以參考的在Python下進行自然語言處理的書籍是由Steven Bird、Ewan Klein、Edward Loper編寫的《Python 自然語言處理》。但是該書的編寫時間距今已有近十年的時間,由於軟體包更新等語言,在新環境下進行開發時,書中的某些程式碼並不能很正常的執行。最後,我們舉一個書中程式碼out of date的例子(對上面這就話進行分詞),並給出相應的解決辦法。首先來看書中的一段節錄

>>> text = 'That U.S.A. poster-print costs $12.40...'
>>> pattern = r'''(?x)    # set flag to allow verbose regexps
...     ([A-Z]\.)+        # abbreviations, e.g. U.S.A.
...   | \w+(-\w+)*        # words with optional internal hyphens
...   | \$?\d+(\.\d+)?%?  # currency and percentages, e.g. $12.40, 82%
...   | \.\.\.            # ellipsis
...   | [][.,;"'?():-_`]  # these are separate tokens; includes ], [
... '''
>>> nltk.regexp_tokenize(text, pattern)


我們預期得到輸出應該是這樣的

['That', 'U.S.A.', 'poster-print', 'costs', '$12.40', '...']


但是我們實際得到的輸出卻是這樣的(注意我們所使用的NLTK版本)

[('', '', ''),
 ('A.', '', ''),
 ('', '-print', ''),
 ('', '', ''),
 ('', '', '.40'),
 ('', '', '')]
會出現這樣的問題是由於nltk.internals.compile_regexp_to_noncapturing()在V3.1版本的NLTK中已經被拋棄(儘管在更早的版本中它仍然可以執行),為此我們把之前定義的pattern稍作修改
pattern = r"""(?x)                   # set flag to allow verbose regexps
              (?:[A-Z]\.)+           # abbreviations, e.g. U.S.A.
              |\d+(?:\.\d+)?%?       # numbers, incl. currency and percentages
              |\w+(?:[-']\w+)*       # words w/ optional internal hyphens/apostrophe
              |\.\.\.                # ellipsis
              |(?:[.,;"'?():-_`])    # special characters with meanings
            """

再次執行前面的語句,便會得到
>>> nltk.regexp_tokenize(text, pattern)
['That', 'U.S.A.', 'poster-print', 'costs', '12.40', '...']

以上便是我們對NLTK這個自然語言處理工具包的初步探索,日後主頁君將結合機器學習中的方法再來探討一些更為深入的應用。最後,我想說《Python 自然語言處理》仍然是當前非常值得推薦的一本講述利用NLTK和Python進行自然語言處理技術的非常值得推薦的書籍。