「認知」的核心技術是天然語言處理,這是人工智能領域中的一個重要方向,研究各類理論和方法,涉及的領域較多,主要包括機器翻譯、閱讀理解、智能寫做、對話系統、基礎技術和語義計算等。css
計算機能「理解並開口說話」,意味着與人類可進行更普遍的交流,從而一步步逼近並超越「圖靈測試」,讓人工智能掀開新的篇章。html
《Python和NLTK天然語言處理》python
做者 [印度] 尼天•哈登尼亞(Nitin Hardeniya) 雅各布•帕金斯(Jacob Perkins) 迪蒂•喬普拉(Deepti Chopra) 尼什•斯喬希(Nisheeth Joshi) 伊提•摩突羅(Iti Mathur)linux
語言是咱們平常生活的核心部分,處理與語言相關的任何問題都是很是有趣的。我但願此書可以讓你一嗅NLP的芬芳,激勵你去了解更使人驚奇的NLP概念,並鼓勵你開發一些具備挑戰性的NLP應用。程序員
研究人類語言的過程稱爲NLP。深刻研究語言的人稱爲語言學家,而「計算語言學家」這個專有名詞適用於應用計算研究語言處理的人。從本質上講,計算語言學家是深刻了解語言的計算機科學家,計算語言學家能夠運用計算技能,對語言的不一樣方面進行建模。計算語言學家解決的是語言理論方面的問題,NLP只不過是計算語言學的應用。web
NLP更多探討的是應用計算機,處理不一樣語言的細微差異,以及使用NLP技術構建現實世界的應用。在實際情景下,NLP相似於教孩子學語言。一些最多見的任務(如理解單詞和句子,造成在語法和結構上正確的句子)對人類而言是很天然。在NLP領域,把這樣的一些任務轉化爲標記解析(tokenization)、組塊(chunking)、詞性標註(part of speech tagging)、解析(parsing)、機器翻譯(machine translation)、語音識別(speech recognition),這些任務中的大部分依然是計算機所面臨的最嚴峻的挑戰。正則表達式
本文主要內容以下。算法
若是你歷來沒有據說過NLP這個詞,那麼請花一些時間來閱讀這裏提到的任何一本書籍,只要閱讀最初幾章便可。至少要快速閱讀一些與NLP相關的維基百科網頁。express
本節從Gartner的技術成熟度曲線開始討論,從這條曲線上,你能夠清楚地看到NLP處在技術成熟度曲線的頂部。目前,NLP是行業所需的稀有技能之一。在大數據到來以後,NLP面臨的主要的挑戰是,NLP須要大量不但精通結構化數據並且擅長於處理半結構化或非結構化數據的技術人員。咱們正在生成拍字節量級的網絡博客、推特信息、臉書(Facebook)的推送信息、聊天記錄、電子郵件和評論。一些公司正在收集全部這些不一樣種類的數據,以便更好地爲客戶定位,並從中獲得有意義的看法。爲了處理這些非結構化數據源,咱們須要瞭解NLP的技術人員。編程
咱們身處信息時代;咱們甚至不能想象生活中沒有谷歌。咱們使用Siri來處理大多數基本的語音功能。咱們使用垃圾郵件過濾器過濾垃圾郵件。在Word文檔中,咱們須要拼寫檢查器。在咱們周圍,存在許多NLP在現實世界中應用的例子。
(圖片來自gartner網站)
下面也提供一些你可以使用可是沒有意識它們是創建在NLP上的使人讚歎的NLP應用的示例。
構建這些應用須要一種很是特殊的技能集,你須要對語言很是瞭解,並具備能夠有效處理語言的工具。所以,讓NLP成爲最具優點的領域之一的緣由不是廣告宣傳,而是可使用NLP建立的這種應用使得NLP成爲必備的最獨特技能之一。
爲了實現上述的一些應用,以及其餘基本的NLP預處理,咱們有不少可用的開源工具。在這些工具中,有一些是某些組織爲創建本身的NLP應用而開發的,而有一些是開源的。這裏是一張可用的NLP工具列表。
大部分工具是用Java編寫的,具備類似的功能。其中一些工具很是健壯,能夠得到NLP工具的不一樣版本。可是,當涉及易於使用和易於解釋這兩個概念的時候,NLTK得分最高。因爲Python(NLTK的編碼語言)的學習曲線很是快,所以NLTK也是很是易於學習的工具包。NLTK已經將大部分的NLP任務歸入籃中,很是優雅,容易用於工做中。出於全部這些緣由,NLTK已成爲NLP界最流行的庫之一。
建議使用Anaconda和Canopy Python的發行版本。理由是,這些版本綁定了一些庫,如scipy、numpy、scikit等,你可使用這些庫進行數據分析,開發出與NLP有關的應用,以及把這些庫應用於相關領域。即便NLTK也是這個發行版本的一部分。
下面測試全部功能。
請在相應的操做系統中,啓動終端。而後運行:
$ python複製代碼
這應該打開了Python解釋器。
1Python 2.6.6 (r266:84292, Oct 15 2013, 07:32:41)
2[GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2
3Type "help", "copyright", "credits" or "license" for more information.
4>>>複製代碼
我但願你獲得的輸出與這個相似。你有可能獲得一個不一樣的輸出,可是在理想狀況下,你得到了Python的最新版本(建議的版本是2.7)信息、編譯器GCC的信息,以及操做系統的詳細信息。Python的最新版本是3.0+,可是,與任何其餘開源的系統同樣,咱們應該試圖保持相對穩定的版本,而不是跳躍到最新版本。若是你已經使用了Python 3.0+,那麼請從python網站了解新版本中又添加了哪些新特徵。
基於UNIX的系統將Python做爲默認程序。Windows用戶能夠設置路徑,讓Python正常運行。下面檢查一下是否已經正確安裝了NLTK。
1>>>import nltk
2>>>print "Python and NLTK installed successfully"
3Python and NLTK installed successfully複製代碼
咱們準備好了。
本節不會深刻探討Python。然而,咱們會讓你快速瀏覽一遍Python的基本知識。一樣,爲了讀者的利益,我認爲應該來一段5分鐘的Python之旅。接下來的幾節將談論數據結構的基本知識、一些經常使用的函數,以及Python的通常構建方式。
在Python中,列表是最經常使用的數據結構之一。它們幾乎至關於其餘編程語言中的數組。下面從Python列表所提供的一些最重要的函數開始講述。
在Python控制檯中,嘗試輸入如下內容。
11>>> lst=[1,2,3,4]
22>>> # mostly like arrays in typical languages
33>>>print lst
44[1, 2, 3, 4]複製代碼
可使用更加靈活的索引來訪問Python列表。下面是一些例子。
>>>print 'First element' +lst[0]複製代碼
你會獲得這樣的錯誤消息:
TypeError: cannot concatenate 'str' and 'int' objects複製代碼
緣由是Python是一種解釋性語言,咱們在聲明變量時,不須要初始化變量並聲明變量的類型,Python只有在計算表達式時,才檢查變量類型。在列表中,對象是整數類型的,所以它們不能與print函數串接。這個函數只接受字符串對象。出於這個緣由,咱們須要將列表元素轉換爲字符串。這個過程也稱爲強制類型轉換(typecasting)。
1>>>print 'First element :' +str(lst[0])
2>>>print 'last element :' +str(lst[-1])
3>>>print 'first three elements :' +str(lst[0:2])
4>>>print 'last three elements :'+str(lst[-3:])
5First element :1
6last element :4
7first three elements :[1, 2,3]
8last three elements :[2, 3, 4]複製代碼
瞭解更多不一樣的數據類型和函數的最佳方法是使用幫助函數,如help() 和 dir(lst)。
可使用dir(Python對象)命令,列出給定Python對象的全部給定的屬性。若是傳入一個列表對象,那麼這個函數會列出全部可使用列表執行的酷炫的操做。
1>>>dir(lst)
2>>>' , '.join(dir(lst))
3'__add__ , __class__ , __contains__ , __delattr__ , __delitem__ , __ 4delslice__ , __doc__ , __eq__ , __format__ , __ge__ , __getattribute__ 5, __getitem__ , __getslice__ , __gt__ , __hash__ , __iadd__ , __imul__ 6, __init__ , __iter__ , __le__ , __len__ , __lt__ , __mul__ , __ne__ , 7__new__ , __reduce__ , __reduce_ex__ , __repr__ , __reversed__ , __rmul__ 8, __setattr__ , __setitem__ , __setslice__ , __sizeof__ , __str__ , __ 9subclasshook__ , append , count , extend , index , insert , pop , remove 10, reverse , sort'複製代碼
使用help(Python對象)命令,咱們能夠獲得給定Python對象的詳細文檔,而且這個命令也給出一些示例,告訴咱們如何使用Python對象。
1>>>help(lst.index)
Help on built-in function index:
index(...)
4 L.index(value, [start, [stop]]) -> integer -- return first index of value.
This function raises a ValueError if the value is not present.複製代碼
所以,在Python的任何數據類型上,均可以使用help和dir,而且這是一種很是不錯的方式,可用於瞭解關於函數和對象的其餘詳細信息。這也提供了一些基本示例,供你在工做中參考,在大部分狀況下,這些示例很是有用。
在Python和其餘語言中,字符串都很是類似,可是對字符串的操做是Python的主要特徵之一。在Python中,使用字符串很是容易。在Java/C中,即便是一些很簡單的操做(例如將字符串分割),咱們也須要花很大的精力才能作到。然而,在Python中,你會發現這是多麼容易。
在應用任何Python對象和函數時,你均可以從先前的help函數中得到幫助。下面使用最經常使用的數據類型字符串給你提供更多的例子。
1 >>> mystring="Monty Python ! And the holy Grail ! \n"
2 >>> print mystring.split()
3 ['Monty', 'Python', '!', 'and', 'the', 'holy', 'Grail', '!']複製代碼
1 >>> print mystring.strip()
2 >>>Monty Python ! and the holy Grail !複製代碼
你是否發現'\n'字符被移除了?還有其餘方法(如lstrip()和rstrip())能夠移除字符串左側和右側的尾隨空格。
1 >>> print (mystring.upper()
2 >>>MONTY PYTHON !AND THE HOLY GRAIL !複製代碼
1 >>> print mystring.replace('!','''''')
2 >>> Monty Python and the holy Grail複製代碼
剛纔談到的是一些最經常使用的字符串函數,函數庫中還存在大量的字符串函數。
提示:要了解更多函數和示例,請瀏覽Python網站。
NLP發燒友的另一個重要技能是使用正則表達式工做。正則表達式描述了字符串的有效模式匹配。咱們大量使用模式提取從衆多雜亂無章的文本數據中得到有意義的信息。如下是讀者所須要的正則表達式。在我一輩子中,我所用的正則表達式都不會超過這個範圍。
例如,要匹配$符號,能夠在它前面加上\。
在現行的例子(即mystring是相同的字符串對象)中,搜索一些內容,而且試圖在此字符串對象上尋找一些模式。子字符串搜索是re模塊的其中一個通用用例。下面實現這一功能。
1>>># We have to import re module to use regular expression
2>>>import re
3>>>if re.search('Python',mystring):
4>>> print "We found python "
5>>>else:
6>>> print "NO "複製代碼
一旦執行代碼,獲得的消息以下。
We found python複製代碼
可使用正則表達式進行更多的模式查找。爲了找到字符串中的全部模式,咱們使用的其中一個普通的函數是findall。這個函數搜索字符串中特定的模式,而且會給出一個包含全部匹配對象的列表。
1>>>import re
2>>>print re.findall('!',mystring)
3['!', '!']複製代碼
正如咱們所見,在mystring中,有兩個「!」實例,findall使用一個列表,返回了這兩個對象。
詞典是另外一種最經常使用的數據結構,在其餘編程語言中,這也稱爲關聯數組/關聯記憶(associative array/memory)。詞典是使用鍵(key)進行索引的數據結構,這些鍵能夠是任何不可變的類型,如字符串和數字能夠用做鍵。
詞典是很是方便的數據結構,普遍應用於各類編程語言中來實現多種算法。在衆多的編程語言中,Python詞典是其中一個優雅地實現了散列表的詞典。在其餘語言中,相同的任務,可能須要花費更多的時間進行更繁重的編碼工做,可是使用詞典,工做就變得很是容易。最棒的事情是,程序員僅僅使用少許的代碼塊,就能夠創建很是複雜的數據結構。這使得程序員擺脫了數據結構自己,花更多時間專一於算法。
我使用詞典中一個很常見的用例,在給定的文本中,得到單詞的頻率分佈。使用如下幾行代碼,就能夠獲得單詞的頻率。你可試着使用任意其餘的語言執行相同的任務,立刻就會明白Python是多麼讓人讚歎不已。
1>>># declare a dictionary
2>>>word_freq={}
3>>>for tok in string.split():
4>>> if tok in word_freq:
5>>> word_freq [tok]+=1
6>>> else:
7>>> word_freq [tok]=1
8>>>print word_freq
9{'!': 2, 'and': 1, 'holy': 1, 'Python': 1, 'Grail': 1, 'the': 1, 'Monty':
101}複製代碼
正如其餘編程語言,Python也有其編寫函數的方式。在Python中,函數以關鍵字def開始,而後是函數名和圓括號()。這與其餘編程語言類似,即任何參數和參數的類型都放在圓括號內。實際的代碼以冒號(:)開頭。代碼的初始行一般是文檔字符串(註釋),而後纔是代碼體,函數使用return語句結束。例如,在給定的例子中,函數wordfreq以def關鍵字開始,這個函數沒有參數,而且以return語句結束。
1>>>import sys
2>>>def wordfreq (mystring):
3>>> ''' 4>>> Function to generated the frequency distribution of the given text 5>>> '''
6>>> print mystring
7>>> word_freq={}
8>>> for tok in mystring.split():
9>>> if tok in word_freq:
10>>> word_freq [tok]+=1
11>>> else:
12>>> word_freq [tok]=1
13>>> print word_freq
14>>>def main():
15>>> str="This is my fist python program"
16>>> wordfreq(str)
17>>>if __name__ == '__main__':
18>>> main()複製代碼
這與上一節中所寫的代碼是相同的,使用函數的形式進行編寫的思想使得代碼可重用和可讀。雖然在編寫Python代碼時解釋器方式也很常見,可是對於大型程序,使用函數/類是一種很是好的作法,這也是一種編程範式。咱們也但願用戶可以編寫和運行第一個Python程序。你須要按照下列步驟來實現這一目標。
(1)在首選的文本編輯器中,打開一個空的Python文件mywordfreq.py。
(2)編寫或複製以上代碼段中的代碼到文件中。
(3)在操做系統中,打開命令提示符窗口。
(4)運行如下命令。
$ python mywordfreq,py "This is my fist python program !!"複製代碼
(5)輸出應該爲:
{'This': 1, 'is': 1, 'python': 1, 'fist': 1, 'program': 1, 'my': 1}複製代碼
如今,對Python提供的一些常見的數據結構,你有了一個很是基本的瞭解。你能夠寫一個完整而且可以運行的Python程序。我認爲這些已經足夠了,使用這些Python的入門知識,你能夠看懂本書前幾章。
提示:請觀看維基百科網站中的一些Python教程,學習更多的Python命令。
無須進一步研究天然語言處理的理論,下面開始介紹NLTK。咱們從一些NLTK的基本示例用例開始。大家中的一些人,可能已經作過了相似的事情。首先,本節會給出一些典型Python程序員的作法,而後會轉到NLTK,尋找一個更加高效、更增強大和更加清晰的解決方案。
下面從某個示例文本內容的分析開始。對於當前的例子,從Python的主頁上得到了一些內容以下所示。
1>>>import urllib2
2>>># urllib2 is use to download the html content of the web link
3>>>response = urllib2.urlopen('http://python.org/')
4>>># You can read the entire content of a file using read() method
5>>>html = response.read()
6>>>print len(html)
747020複製代碼
因爲咱們對在這個URL中所討論的主題類型沒有任何線索,所以從探索性數據分析(EDA)開始。通常來講,在文本領域,EDA具備多種含義,可是這裏討論一種簡單的狀況,即在文檔中,何種術語佔據了主導地位。主題是什麼?它們出現的頻率有多大?這一過程將涉及某種層次的預處理步驟。咱們首先使用純Python方式,嘗試執行這個任務,而後會使用NLTK執行這個任務。
讓咱們從清理HTML標籤開始。完成這個任務的一種方式是僅僅選擇包括了數字和字符的標記(token)。任何可以使用正則表達式工做的人員應該可以將HTML字符串轉換成標記列表。
1>>># Regular expression based split the string
2>>>tokens = [tok for tok in html.split()]
3>>>print "Total no of tokens :"+ str(len(tokens))
4>>># First 100 tokens
5>>>print tokens[0:100]
6Total no of tokens :2860
7['', '', '', ''type="text/css"', 'media="not', 'print,', 'braille,'...] 8 複製代碼
正如你所看到的,使用前面的方法,存在過量的HTML標籤和其餘可有可無的字符。執行同一任務的相對清潔的版本,以下所示。
1>>>import re
2>>># using the split function
3>>>#https://docs.python.org/2/library/re.html
4>>>tokens = re.split('\W+',html)
5>>>print len(tokens)
6>>>print tokens[0:100]
75787
8['', 'doctype', 'html', 'if', 'lt', 'IE', '7', 'html', 'class', 'no',
9'js', 'ie6', 'lt', 'ie7', 'lt', 'ie8', 'lt', 'ie9', 'endif', 'if',
10'IE', '7', 'html', 'class', 'no', 'js', 'ie7', 'lt', 'ie8', 'lt', 'ie9',
11'endif', 'if', 'IE', '8', 'msapplication', 'tooltip', 'content', 'The',
12'official', 'home', 'of', 'the', 'Python', 'Programming', 'Language',
13'meta', 'name', 'apple' ...]複製代碼
如今,這看起來清爽多了。可是,你能夠作更多的事情,使代碼變得更加簡潔。這裏將這項工做留給你,讓你嘗試移除儘量多的噪聲。能夠清除一些仍然彈出的HTML標籤。在這個例子中,字長爲1的單詞(如7和8這樣的元素)僅僅是噪聲,你可能但願以字長做爲標準,移除這些單詞。如今,與其從頭開始編寫一些預處理步驟的代碼,不如將目光轉移到NLTK,使用NTLK執行相同的任務。有一個函數clean_html(),這個函數能夠執行所須要的全部清潔工做。
1>>>import nltk
2>>># http://www.nltk.org/api/nltk.html#nltk.util.clean_html
3>>>clean = nltk.clean_html(html)
4>>># clean will have entire string removing all the html noise
5>>>tokens = [tok for tok in clean.split()]
6>>>print tokens[:100]
7['Welcome', 'to', 'Python.org', 'Skip', 'to', 'content', '▼',
8'Close', 'Python', 'PSF', 'Docs', 'PyPI', 'Jobs', 'Community', '▲',
9'The', 'Python', 'Network', '≡', 'Menu', 'Arts', 'Business' ...]複製代碼
這很酷炫,對吧?這種方法絕對更加清潔,也更容易執行。
下面嘗試得到這些術語的頻率分佈。首先,咱們使用純Python的方式執行這個任務,而後,我將告訴你NLTK的祕訣。
1>>>import operator
2>>>freq_dis={}
3>>>for tok in tokens:
4>>> if tok in freq_dis:
5>>> freq_dis[tok]+=1
6>>> else:
7>>> freq_dis[tok]=1
8>>># We want to sort this dictionary on values ( freq inthis case )
9>>>sorted_freq_dist= sorted(freq_dis.items(), key=operator.itemgetter(1),
10reverse=True)
11>>> print sorted_freq_dist[:25]
12[('Python', 55), ('>>>', 23), ('and', 21), ('to', 18), (',', 18), ('the',
1314), ('of', 13), ('for', 12), ('a', 11), ('Events', 11), ('News', 11),
14('is', 10), ('2014-', 10), ('More', 9), ('#', 9), ('3', 9), ('=', 8),
15('in', 8), ('with', 8), ('Community', 7), ('The', 7), ('Docs', 6),
16('Software', 6), (':', 6), ('3:', 5), ('that', 5), ('sum', 5)]複製代碼
天然而然地,因爲這是Python主頁,所以Python和(>>>)解釋器符號是最多見的術語,這也展現了網站的第一感受。
一個更好而且更有效的方法是使用NLTK的FreqDist()函數。爲了進行對比,咱們能夠觀察以前開發的執行相同任務的代碼。
1>>>import nltk
2>>>Freq_dist_nltk=nltk.FreqDist(tokens)
3>>>print Freq_dist_nltk
4>>>for k,v in Freq_dist_nltk.items():
5>>> print str(k)+':'+str(v)
6>>': 23, 'and': 21, ',': 18, 'to': 18, 'the': 714, 'of': 13, 'for': 12, 'Events': 11, 'News': 11, ...> 8Python:55 9>>>:23 10and:21 11,:18 12to:18 13the:14 14of:13 15for:12 16Events:11 17News:11 18複製代碼
如今,讓咱們作一些更有趣的事情,畫出這些頻率分佈。
1>>>Freq_dist_nltk.plot(50, cumulative=False)
2>>># below is the plot for the frequency distributions複製代碼
能夠看到,累積頻率持續增加,總體上,曲線有一條長長的尾巴。一些噪聲依然存在,一些單詞(如the、of、for和=)是毫無用處的。對於這些單詞(如the、a、an等),使用術語停用詞(stop word)來稱呼它們。因爲在大部分文檔中不定代詞通常都會出現,所以這些詞沒有什麼判別力,不能傳達太多的信息。在大多數的NLP和信息檢索任務中,人們一般會刪除停用詞。讓咱們再次回到當前的示例中。
1>>>stopwords=[word.strip().lower() for word in open("PATH/english.stop. 2txt")]
3>>>clean_tokens=[tok for tok in tokens if len(tok.lower())>1 and (tok.
4lower() not in stopwords)]
5>>>Freq_dist_nltk=nltk.FreqDist(clean_tokens)
6>>>Freq_dist_nltk.plot(50, cumulative=False)複製代碼
如今,這看起來乾淨多了!在完成了這麼多任務後,能夠訪問Wordle,將頻率分佈轉換成CSV格式。你應該可以獲得如下詞雲。
書號:978-7-115-50334-3
推薦理由:NLTK是天然語言處理領域中很是受歡迎和普遍使用的Python庫。NLTK的優勢在於其簡單性,其中大多數複雜的天然語言處理任務使用幾行代碼便可完成。本書旨在講述如何用Python和NLTK解決各類天然語言處理任務並開發機器學習方面的應用。本書介紹了NLTK的基本模塊,講述了採用NLTK實現天然語言處理的大量技巧,討論了一些文本處理方法和語言處理技術,展現了使用Python實現NLP項目的大量實踐經驗。本書主要內容包括文本挖掘/NLP任務中所需的全部預處理步驟,如何使用Python 3的NLTK 3進行文本處理,如何經過Python開展NLP項目。
本書適合NLP和機器學習領域的愛好者、Python程序員以及機器學習領域的研究人員閱讀。
- END -