国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python中一些自然語言工具的使用的入門教程

2019-11-25 17:45:17
字體:
來源:轉載
供稿:網友

NLTK 是使用 Python 教學以及實踐計算語言學的極好工具。此外,計算語言學與人工 智能、語言/專門語言識別、翻譯以及語法檢查等領域關系密切。
NLTK 包括什么

NLTK 會被自然地看作是具有棧結構的一系列層,這些層構建于彼此基礎之上。那些熟悉人工語言(比如 Python)的文法 和解析的讀者來說,理解自然語言模型中類似的 ―― 但更深奧的 ―― 層不會有太大困難。
術語表

全集(Corpora):相關文本的集合。例如,莎士比亞的作品可能被統稱為一個 文集(corpus); 而若干個作者的作品稱為 全集。

直方圖(Histogram):數據集中不同單詞、字母或其他條目的出現頻率的統計分布。

結構(Syntagmatic):對語段的研究;也就是全集中字母、單詞或短語連續出現的統計關系。

上下文無關語法(Context-free grammar): 由四類形式語法構成的 Noam Chomsky 層級中的第二類。參閱 參考資料 以獲得 詳盡描述。

盡管 NLTK 附帶了很多已經預處理(通常是手工地)到不同程度的全集,但是概念上每一層 都是依賴于相鄰的更低層次的處理。首先是斷詞;然后是為單詞加上 標簽;然后將成組 的單詞解析為語法元素,比如名詞短語或句子(取決于幾種技術中的某一種,每種技術都有其優缺點); 最后對最終語句或其他語法單元進行分類。通過這些步驟,NLTK 讓您可以生成關于不同元素出現情況 的統計,并畫出描述處理過程本身或統計合計結果的圖表。

在本文中,您將看到關于低層能力的一些相對完整的示例,而對大部分高層次能力將只是進行簡單抽象的描述。 現在讓我們來詳細分析文本處理的首要步驟。

斷詞(Tokenization)

您可以使用 NLTK 完成的很多工作,尤其是低層的工作,與使用 Python 的基本數據結構來完成相比,并 沒有 太 大的區別。不過,NLTK 提供了一組由更高的層所依賴和使用的系統化的接口,而不只是 簡單地提供實用的類來處理加過標志或加過標簽的文本。

具體講, nltk.tokenizer.Token 類被廣泛地用于存儲文本的有注解的片斷;這些 注解可以標記很多不同的特性,包括詞類(parts-of-speech)、子標志(subtoken)結構、一個標志(token) 在更大文本中的偏移位置、語形詞干 (morphological stems)、文法語句成分,等等。實際上,一個 Token 是一種 特別的字典 ―― 并且以字典形式訪問 ―― 所以它可以容納任何您希望的鍵。在 NLTK 中使用了一些專門的鍵, 不同的鍵由不同的子程序包所使用。

讓我們來簡要地分析一下如何創建一個標志并將其拆分為子標志:
清單 1. 初識 nltk.tokenizer.Token 類

>>> from nltk.tokenizer import *>>> t = Token(TEXT='This is my first test sentence')>>> WSTokenizer().tokenize(t, addlocs=True) # break on whitespace>>> print t['TEXT']This is my first test sentence>>> print t['SUBTOKENS'][<This>@[0:4c], <is>@[5:7c], <my>@[8:10c], <first>@[11:16c],<test>@[17:21c], <sentence>@[22:30c]]>>> t['foo'] = 'bar'>>> t<TEXT='This is my first test sentence', foo='bar',SUBTOKENS=[<This>@[0:4c], <is>@[5:7c], <my>@[8:10c], <first>@[11:16c],<test>@[17:21c], <sentence>@[22:30c]]>>>> print t['SUBTOKENS'][0]<This>@[0:4c]>>> print type(t['SUBTOKENS'][0])<class 'nltk.token.SafeToken'>

概率(Probability)

對于語言全集,您可能要做的一件相當簡單的事情是分析其中各種 事件(events) 的 頻率分布,并基于這些已知頻率分布做出概率預測。NLTK 支持多種基于自然頻率分布數據進行概率預測的方法。 我將不會在這里介紹那些方法(參閱 參考資料 中列出的概率教程), 只要說明您肯定會 期望的那些與您已經 知道的 那些(不止是顯而易見的 縮放比例/正規化)之間有著一些模糊的關系就夠了。

基本來講,NLTK 支持兩種類型的頻率分布:直方圖和條件頻率分布(conditional frequency)。 nltk.probability.FreqDist 類用于創建直方圖;例如, 可以這樣創建一個單詞直方圖:
清單 2. 使用 nltk.probability.FreqDist 創建基本的直方圖

>>> from nltk.probability import *>>> article = Token(TEXT=open('cp-b17.txt').read())>>> WSTokenizer().tokenize(article)>>> freq = FreqDist()>>> for word in article['SUBTOKENS']:...   freq.inc(word['TEXT'])>>> freq.B()1194>>> freq.count('Python')12

概率教程討論了關于更復雜特性的直方圖的創建,比如“以元音結尾的詞后面的詞的長度”。 nltk.draw.plot.Plot 類可用于直方圖的可視化顯示。當然, 您也可以這樣分析高層次語法特性或者甚至是與 NLTK 無關的數據集的頻率分布。

條件頻率分布可能比普通的直方圖更有趣。條件頻率分布是一種二維直方圖 ―― 它按每個初始條件或者“上下文”為您顯示 一個直方圖。例如,教程提出了一個對應每個首字母的單詞長度分布問題。我們就以這樣分析:
清單 3. 條件頻率分布:對應每個首字母的單詞長度

>>> cf = ConditionalFreqDist()>>> for word in article['SUBTOKENS']:...   cf[word['TEXT'][0]].inc(len(word['TEXT']))...>>> init_letters = cf.conditions()>>> init_letters.sort()>>> for c in init_letters[44:50]:...   print "Init %s:" % c,...   for length in range(1,6):...     print "len %d/%.2f," % (length,cf[c].freq(n)),...   print...Init a: len 1/0.03, len 2/0.03, len 3/0.03, len 4/0.03, len 5/0.03,Init b: len 1/0.12, len 2/0.12, len 3/0.12, len 4/0.12, len 5/0.12,Init c: len 1/0.06, len 2/0.06, len 3/0.06, len 4/0.06, len 5/0.06,Init d: len 1/0.06, len 2/0.06, len 3/0.06, len 4/0.06, len 5/0.06,Init e: len 1/0.18, len 2/0.18, len 3/0.18, len 4/0.18, len 5/0.18,Init f: len 1/0.25, len 2/0.25, len 3/0.25, len 4/0.25, len 5/0.25,

條件頻率分布在語言方面的一個極好應用是分析全集中的語段分布 ―― 例如,給出一個特定的 詞,接下來最可能出現哪個詞。當然,語法會帶來一些限制;不過,對句法選項的選擇的研究 屬于語義學、語用論和術語范疇。

詞干提取(Stemming)

nltk.stemmer.porter.PorterStemmer 類是一個用于從英文單詞中 獲得符合語法的(前綴)詞干的極其便利的工具。這一能力尤其讓我心動,因為我以前曾經用 Python 創建了一個公用的、全文本索引的 搜索工具/庫(見 Developing a full-text indexer in Python 中的描述,它已經用于相當多的其他項目中)。

盡管對大量文檔進行關于一組確切詞的搜索的能力是非常實用的( gnosis.indexer 所做的工作), 但是,對很多搜索用圖而言,稍微有一些模糊將會有所幫助。也許,您不能特別確定您正在尋找的電子郵件是否使用了單詞 “complicated”、“complications”、“complicating”或者“complicates”,但您卻記得那是大概涉及的內容(可能與其他一些 詞共同來完成一次有價值的搜索)。

NLTK 中包括一個用于單詞詞干提取的極好算法,并且讓您可以按您的喜好定制詞干提取算法:
清單 4. 為語形根(morphological roots)提取單詞詞干

>>> from nltk.stemmer.porter import PorterStemmer>>> PorterStemmer().stem_word('complications')'complic'

實際上,您可以怎樣利用 gnosis.indexer 及其衍生工具或者完全不同的索引工具中的詞干 提取功能,取決于您的使用情景。幸運的是,gnosis.indexer 有一個易于進行專門定制的 開放接口。您是否需要一個完全由詞干構成的索引?或者您是否在索引中同時包括完整的單詞 和詞干?您是否需要將結果中的詞干匹配從確切匹配中分離出來?在未來版本的 gnosis.indexer 中我將引入一些種類詞干的提取能力,不過,最終用戶可能仍然希望進行不同的定制。

無論如何,一般來說添加詞干提取是非常簡單的:首先,通過特別指定 gnosis.indexer.TextSplitter 來從一個文檔中獲得詞干;然后, 當然執行搜索時,(可選地)在使用搜索條件進行索引查找之前提取其詞干,可能是通過定制 您的 MyIndexer.find() 方法來實現。

在使用 PorterStemmer 時我發現 nltk.tokenizer.WSTokenizer 類確實如教程所警告的那樣不好用。它可以勝任概念上的角色,但是對于實際的文本而言,您可以更好地識別出什么是一個 “單詞”。幸運的是, gnosis.indexer.TextSplitter 是一個健壯的斷詞工具。例如:
清單 5. 基于拙劣的 NLTK 斷詞工具進行詞干提取

>>> from nltk.tokenizer import *>>> article = Token(TEXT=open('cp-b17.txt').read())>>> WSTokenizer().tokenize(article)>>> from nltk.probability import *>>> from nltk.stemmer.porter import *>>> stemmer = PorterStemmer()>>> stems = FreqDist()>>> for word in article['SUBTOKENS']:...   stemmer.stem(word)...   stems.inc(word['STEM'].lower())...>>> word_stems = stems.samples()>>> word_stems.sort()>>> word_stems[20:40]['"generator-bas', '"implement', '"lazili', '"magic"', '"partial','"pluggable"', '"primitives"', '"repres', '"secur', '"semi-coroutines."','"state', '"understand', '"weightless', '"whatev', '#', '#-----','#----------', '#-------------', '#---------------', '#b17:']

查看一些詞干,集合中的詞干看起來并不是都可用于索引。很多根本不是實際的單詞,還有其他一些是 用破折號連接起來的組合詞,單詞中還被加入了一些不相干的標點符號。讓我們使用更好的斷詞工具 來進行嘗試:
清單 6. 使用斷詞工具中靈巧的啟發式方法來進行詞干提取

>>> article = TS().text_splitter(open('cp-b17.txt').read())>>> stems = FreqDist()>>> for word in article:...   stems.inc(stemmer.stem_word(word.lower()))...>>> word_stems = stems.samples()>>> word_stems.sort()>>> word_stems[60:80]['bool', 'both', 'boundari', 'brain', 'bring', 'built', 'but', 'byte','call', 'can', 'cannot', 'capabl', 'capit', 'carri', 'case', 'cast','certain', 'certainli', 'chang', 'charm']

在這里,您可以看到有一些單詞有多個可能的擴展,而且所有單詞看起來都像是單詞或者詞素。 斷詞方法對隨機文本集合來說至關重要;公平地講,NLTK 捆綁的全集已經通過 WSTokenizer() 打包為易用且準確的斷詞工具。要獲得健壯的實際可用的索引器,需要使用健壯的斷詞工具。

添加標簽(tagging)、分塊(chunking)和解析(parsing)

NLTK 的最大部分由復雜程度各不相同的各種解析器構成。在很大程度上,本篇介紹將不會 解釋它們的細節,不過,我愿意大概介紹一下它們要達成什么目的。

不要忘記標志是特殊的字典這一背景 ―― 具體說是那些可以包含一個 TAG 鍵以指明單詞的語法角色的標志。NLTK 全集文檔通常有部分專門語言已經預先添加了標簽,不過,您當然可以 將您自己的標簽添加到沒有加標簽的文檔。

分塊有些類似于“粗略解析”。也就是說,分塊工作的進行,或者基于語法成分的已有標志,或者基于 您手工添加的或者使用正則表達式和程序邏輯半自動生成的標志。不過,確切地說,這不是真正的解析 (沒有同樣的生成規則)。例如:
清單 7. 分塊解析/添加標簽:單詞和更大的單位

>>> from nltk.parser.chunk import ChunkedTaggedTokenizer>>> chunked = "[ the/DT little/JJ cat/NN ] sat/VBD on/IN [ the/DT mat/NN ]">>> sentence = Token(TEXT=chunked)>>> tokenizer = ChunkedTaggedTokenizer(chunk_node='NP')>>> tokenizer.tokenize(sentence)>>> sentence['SUBTOKENS'][0](NP: <the/DT> <little/JJ> <cat/NN>)>>> sentence['SUBTOKENS'][0]['NODE']'NP'>>> sentence['SUBTOKENS'][0]['CHILDREN'][0]<the/DT>>>> sentence['SUBTOKENS'][0]['CHILDREN'][0]['TAG']'DT'>>> chunk_structure = TreeToken(NODE='S', CHILDREN=sentence['SUBTOKENS'])(S: (NP: <the/DT> <little/JJ> <cat/NN>) <sat/VBD> <on/IN> (NP: <the/DT> <mat/NN>))

所提及的分塊工作可以由 nltk.tokenizer.RegexpChunkParser 類使用偽正則表達式來描述 構成語法元素的一系列標簽來完成。這里是概率教程中的一個例子:
清單 8. 使用標簽上的正則表達式進行分塊

>>> rule1 = ChunkRule('<DT>?<JJ.*>*<NN.*>',...        'Chunk optional det, zero or more adj, and a noun')>>> chunkparser = RegexpChunkParser([rule1], chunk_node='NP', top_node='S')>>> chunkparser.parse(sentence)>>> print sent['TREE'](S: (NP: <the/DT> <little/JJ> <cat/NN>) <sat/VBD> <on/IN> (NP: <the/DT> <mat/NN>))

真正的解析將引領我們進入很多理論領域。例如,top-down 解析器可以確保找到每一個可能的產品,但 可能會非常慢,因為要頻繁地(指數級)進行回溯。Shift-reduce 效率更高,但是可能會錯過一些產品。 不論在哪種情況下,語法規則的聲明都類似于解析人工語言的語法聲明。本專欄曾經介紹了其中的一些: SimpleParse 、 mx.TextTools 、 Spark 和 gnosis.xml.validity (參閱 參考資料)。

甚至,除了 top-down 和 shift-reduce 解析器以外,NLTK 還提供了“chart 解析器”,它可以創建部分假定, 這樣一個給定的序列就可以繼而完成一個規則。這種方法可以是既有效又完全的。舉一個生動的(玩具級的)例子:
清單 9. 為上下文無關語法定義基本的產品

>>> from nltk.parser.chart import *>>> grammar = CFG.parse('''...  S -> NP VP...  VP -> V NP | VP PP...  V -> "saw" | "ate"...  NP -> "John" | "Mary" | "Bob" | Det N | NP PP...  Det -> "a" | "an" | "the" | "my"...  N -> "dog" | "cat" | "cookie"...  PP -> P NP...  P -> "on" | "by" | "with"...  ''')>>> sentence = Token(TEXT='John saw a cat with my cookie')>>> WSTokenizer().tokenize(sentence)>>> parser = ChartParser(grammar, BU_STRATEGY, LEAF='TEXT')>>> parser.parse_n(sentence)>>> for tree in sentence['TREES']: print tree(S: (NP: <John>) (VP:  (VP: (V: <saw>) (NP: (Det: <a>) (N: <cat>)))  (PP: (P: <with>) (NP: (Det: <my>) (N: <cookie>)))))(S: (NP: <John>) (VP:  (V: <saw>)  (NP:   (NP: (Det: <a>) (N: <cat>))   (PP: (P: <with>) (NP: (Det: <my>) (N: <cookie>))))))

probabilistic context-free grammar(或者說是 PCFG)是一種上下文無關語法, 它將其每一個產品關聯到一個概率。同樣,用于概率解析的解析器也捆綁到了 NLTK 中。

您在等待什么?

NLTK 還有其他本篇簡短介紹中不能涵蓋的重要功能。例如,NLTK 有一個完整的框架,用于通過類似于“naive Bayesian” 和“maximum entropy”等模型的統計技術進行文本分類。 即使還有篇幅,現在我也還不能解釋其本質。不過,我認為,即使是 NLTK 較低的層,也可以成為一個既可用于教學應用程序 也可用于實際應用程序的實用框架。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 眉山市| 礼泉县| 吉林市| 全椒县| 邯郸县| 黎川县| 桑日县| 锦州市| 高唐县| 神农架林区| 松江区| 盱眙县| 浮梁县| 大田县| 滨海县| 陆河县| 独山县| 阳新县| 满洲里市| 鄯善县| 乌拉特中旗| 鄂伦春自治旗| 赫章县| 长宁区| 苏州市| 武鸣县| 南丰县| 塔河县| 西乌珠穆沁旗| 临沭县| 凌海市| 新晃| 麻栗坡县| 金乡县| 宁国市| 拉萨市| 璧山县| 中超| 宝应县| 新沂市| 花莲市|