python nlp包_StanfordNLP,让你在 Python 里一手掌握 53 种自然语言分析
發表日期:2019-06-12
StanfordNLP,讓你在 Python 里一手掌握 53 種自然語言分析
—— 不久之前,斯坦福大學公開了它最新的自然語言處理代碼庫—— StanfordNLP。它不但包含了完整的語義分析工具鏈,還帶有 73 個不同的高精度神經網絡模...
作者:Mohd Sanad Zaki Rizvi
不久之前,斯坦福大學公開了它最新的自然語言處理代碼庫—— StanfordNLP。它不但包含了完整的語義分析工具鏈,還帶有 73 個不同的高精度神經網絡模型,能解析 53 種不同的人類語言。是不是很牛×啊?今天的教程里,優達菌就手把手帶你在 Python 上使用 StanfordNLP,進行一些自然語言處理實戰。
在學習自然語言處理(NLP)的過程中,我們常常會遇到這樣一個問題:“我們能不能為除英語之外的其他語言構建模型呢?”在很長一段時間里,這都是一個難以完成的任務。要知道,每種語言都有自己獨特的語法模式和細微的語言差別,而且除了英語之外,其他語言的數據集實在是少之又少。
但如今,我們有了 StanfordNLP 這一神器。
當我第一次看到 StanfordNLP 的介紹時,我簡直無法抑制自己的激動之情。作者聲稱它可以支持超過 53 中不同的人類語言!(沒錯,你沒看錯,確實是 53 種……我當時也覺得自己一定是眼花了。)
在 StanfordNLP 的官方網站上,作者列出了目前支持的所有 53 種人類語言,其中包含了許多其他 NLP 庫所沒有的語言,比如印地語、日語和我們最愛的中文。這簡直是為我們打開了通往無限可能的新世界的大門啊!
StanfordNLP 到底是何方神圣,我為啥需要用它?
簡單地說,StanfordNLP 是一系列預訓練好的,高水平的神經網絡模型。目前的 73 個模型都是來自 2017、18 年 CoNLL 會議上的研究者。它們都是用 PyTorch 訓練而來的,你也可以用自己的語料庫來訓練和評估它們,是不是很酷炫?
此外,StanfordNLP 還包含了一個官方的 CoreNLP 封裝。CoreNLP 作為一款廣受好評的史詩級 NLP 庫,在此之前,你只能依靠 Java 才能用上它。對有興趣的讀者,我建議你看看這個教程,了解更多有關 CoreNLP 的信息,以及它在 Python 中的工作原理。
對 NLP 愛好者來說,真是沒有比這個更棒的了。現在,就讓我們在 Python 中實際操作一下吧!
在 Python 中安裝設置 StanfordNLP 庫
最初,這個庫里有一些奇怪的東西,讓我感到十分困惑。例如,你需要使用 Python 3.6 / 3.7 或更高版本才能使用 StanfordNLP。為了安全起見,我在 Anaconda 中設置了一個單獨的 Python 3.7.1 環境。具體步驟如下:
打開 conda 命令行,輸入:
conda create -n stanfordnlp python=3.7.1
一般來說一路 yes 到底即可。
接著激活剛建立的環境:
source activate stanfordnlp
conda 4.6 或更高版本可以用:
conda activate stanfordnlp
在新環境里安裝 StanfordNLP 庫:
pip install stanfordnlp
接下來,我們需要下載對應自然語言的模型。打開一個 Python 命令行,導入 StanfordNLP 庫:
import stanfordnlp
接著下載對應的語言模型,以英語(“en”)為例:
stanfordnlp.download('en')
根據你網絡速度的不同,這可能需要花費一些時間。一般來說你得下載大概 300M 的內容。
一些注意事項
StanfordNLP 是基于 PyTorch 1.0.0 構建的。如果你嘗試在更早的版本上運行它,可能會遇到一些奇怪的問題。你可以在命令行運行這樣的命令來檢查你的 PyTorch 版本:
pip freeze | grep torch
正常情況下你應該看到類似 torch==1.0.0 這樣的輸出。
我試過在沒有獨立顯示芯片的機器上跑這個庫,比如我的聯想 Thinkpad E470(8G 內存,英特爾核顯)。
結果是,Python 很快就甩了一個 memory error 給我。因此,我換到一臺有獨立顯卡的機器上來運行這些代碼,我強烈建議你也這么做。
對了,你可以試試 Google 出品的地表最強 Python 編輯器——Google Colab,它提供了 12-14G 的內存,以及免費的 GPU 算力。
好啦,說了這么多,你應該已經裝好了相關的庫和模型了吧?讓我們試著開始一些基本的 NLP 處理吧。
使用 StanfordNLP 完成簡單的 NLP 任務
假設我們要分析一段英文材料,首先,我們需要建立一個文字處理管道(pipeline):
nlp = stanfordnlp.Pipeline(processors = "tokenize,mwt,lemma,pos")
doc = nlp("""The prospects for Britain’s orderly withdrawal from the European Union
on March 29 have receded further, even as MPs rallied to stop a no-deal scenario.
An amendment to the draft bill on the termination of London’s membership of the
bloc obliges Prime Minister Theresa May to renegotiate her withdrawal agreement
with Brussels. A Tory backbencher’s proposal calls on the government to come up
with alternatives to the Irish backstop, a central tenet of the deal Britain agreed
with the rest of the EU.""")
我們通過 processors = "" 參數指定需要分析的具體任務。如果不傳入任何參數,程序將默認調用全部 5 個處理模塊進行分析。具體可見下表:
參數名
標注器類名(Annotator)
工作方式/結果
tokenize
TokenizeProcessor
分詞工具。它將一個文檔( Document )分成許多句子( Sentence ),每個句子都包含著一個分詞結果的列表,列表的元素是 Token。分詞處理器還會預測哪些單詞/字會組成多字詞/詞組,以便后續用 MWT 處理模塊進行擴展。
mwt
MWTProcessor
對上一步預測的多字詞/詞組進行處理,將它們進行擴展。
lemma
LemmaProcessor
利用單詞( Word )的 Word.text 和 Word.upos 屬性,對每個單詞進行詞形還原。處理結果將存放在 Word.lemma 中。
pos
POSProcessor
對每個 token 都進行全局詞性分析(universal POS,UPOS)和基于語料庫的詞性分析(treebank-specific POS,XPOS) 標注,以及全局的形態特征(universal morphological features ,UFeats)標注,最后存放在 Word 對象的 pos 、 xpos 以及 ufeats 屬性中。
depparse
DepparseProcessor
它提供了一個準確的句法依存關系解析器,用來確定句子中每個單詞的句法核心(syntactic head),以及兩個單詞之間的依存關系。分析結果保存在 Word 對象的 governor 和 dependency_relation 屬性中。
讓我們在實戰中檢驗一下這些分析器吧。
分詞處理
當 TokenizeProcessor 運行的時候,分詞處理過程將在后臺運行,事實上,它的處理速度相當快。你可以使用 print_tokens() 方法來查看分詞結果:
doc.sentences[0].print_tokens()
結果就類似上面這樣。每個 token 對象都包含了句子中每個詞的索引,以及一個包含了 Word 對象的列表(以防有一些由多個單詞/字組成的短語/詞組。每一個 Word 對象都包含了詳細的信息,包括序號、單詞原形、詞性、形態特征等標簽。
詞形還原
這就要用到 LemmaProcessor 給每個 Word 對象生成的 lemma 屬性了(參見上面分詞結果圖中的 lemma= 部分)。我們只需要簡單的幾行代碼就可以對所有單詞進行詞形還原:
# 文件名: lemma.py
import pandas as pd
def extract_lemma(doc):
parsed_text = {'word':[], 'lemma':[]}
for sent in doc.sentences:
for wrd in sent.words:
# 提取文本和原形 parsed_text['word'].append(wrd.text)
parsed_text['lemma'].append(wrd.lemma)
# 返回值是一個 DataFrame 對象 return pd.DataFrame(parsed_text)
extract_lemma(doc)
這將返回一個 pandas 的數據表(DataFrame 對象),列出了每個單詞及其對應的單詞原形:
詞性分析與標注
用于詞性分析的 POSProcessor 可以又快又準地處理多種不同語言。和詞形還原一樣,詞性分析的標簽也很容易讀取和輸出:
# 文件名: parts_of_speech.py
# 定義一個存放 POS 值及對應詞性描述的字典對象pos_dict = {
'CC': 'coordinating conjunction',
'CD': 'cardinal digit',
'DT': 'determiner',
'EX': 'existential there (like:\"there is\"... think of it like\"there exists\")',
'FW': 'foreign word',
'IN': 'preposition/subordinating conjunction',
'JJ': 'adjective\'big\'',
'JJR': 'adjective, comparative\'bigger\'',
'JJS': 'adjective, superlative\'biggest\'',
'LS': 'list marker 1)',
'MD': 'modal could, will',
'NN': 'noun, singular\'desk\'',
'NNS': 'noun plural\'desks\'',
'NNP': 'proper noun, singular\'Harrison\'',
'NNPS': 'proper noun, plural\'Americans\'',
'PDT': 'predeterminer\'all the kids\'',
'POS': 'possessive ending parent\'s',
'PRP': 'personal pronoun I, he, she',
'PRP$': 'possessive pronoun my, his, hers',
'RB': 'adverb very, silently,',
'RBR': 'adverb, comparative better',
'RBS': 'adverb, superlative best',
'RP': 'particle give up',
'TO': 'to go\'to\'the store.',
'UH': 'interjection errrrrrrrm',
'VB': 'verb, base form take',
'VBD': 'verb, past tense took',
'VBG': 'verb, gerund/present participle taking',
'VBN': 'verb, past participle taken',
'VBP': 'verb, sing. present, non-3d take',
'VBZ': 'verb, 3rd person sing. present takes',
'WDT': 'wh-determiner which',
'WP': 'wh-pronoun who, what',
'WP$': 'possessive wh-pronoun whose',
'WRB': 'wh-abverb where, when',
'QF' : 'quantifier, bahut, thoda, kam (Hindi)',
'VM' : 'main verb',
'PSP' : 'postposition, common in indian langs',
'DEM' : 'demonstrative, common in indian langs'
}
def extract_pos(doc):
parsed_text = {'word':[], 'pos':[], 'exp':[]}
for sent in doc.sentences:
for wrd in sent.words:
if wrd.pos in pos_dict.keys():
pos_exp = pos_dict[wrd.pos]
else:
pos_exp = 'NA'
parsed_text['word'].append(wrd.text)
parsed_text['pos'].append(wrd.pos)
parsed_text['exp'].append(pos_exp)
return pd.DataFrame(parsed_text)
extract_pos(doc)
注意到上面那個巨大的字典對象了嗎?那是為了把詞性分析的標簽和人類能懂的描述一一對應起來。這能讓我們更好地理解文件的語法結構。
程序將輸出一個數據表對象,其中包含 3 列:單詞(Word)、詞性(pos)以及對應的解釋(exp)。解釋列中的內容包含了最多的語義信息,也是對我們最有用的部分。
增加了解釋列之后,我們就能更容易地看出分析器處理詞句時的準確性如何。讓我欣喜的是,絕大部分的詞語都能夠被正確地標記起來,它甚至能正確地判斷出一個詞的時態和詞性,包括它是單數還是復數形式等。
依存關系解析
依存關系解析也是 StanfordNLP 里開箱即用的工具之一。你只需要在程序中調用 print_dependencies() 方法,就能方便地獲取到句子中所有元素的依存關系:
doc.sentences[0].print_dependencies()
總的來說,程序將在一次管道處理過程中計算上述的每一個步驟。對于能使用 GPU 的機器來說,整個運算過程一般要不了幾分鐘就能搞定。
于是,我們已經摸清了用 StanfordNLP 庫完成簡單文字處理任務的基本操作,現在我們該試試在各種不同語言上進行同樣的操作啦!
對印地語使用 StanfordNLP 進行處理
StanfordNLP 在處理性能和多語言文本解析支持方面都擁有非常突出的表現。我們現在就來深入研究一下后面這部分。
處理印地語文字(梵文文本)
首先,我們先下載印地語的模型(相對來說小多了!):
stanfordnlp.download('hi')
接著,把一段印地語文字放進去,作為目標文本:
hindi_doc = nlp("""?????? ?? ???? ????? ?? ???????? ?? ???? ?????? ??? ??? ????. ????????? ????? ?????? ????? ???? ?? ???? ??? ??? ?????, ?????, ??????, ????? ???? ???? ?? ???? ?? ??? ???? ???? ???. ???????, ??? ?? ??? ?? ????? ?? ???? ???? ????????? ??? ???. ?????? ????? ?? ?? ?????? ??? ???? ??? ??? ?? ????? ???? ????, ???? ???? ??? ???? ?????""")
要生成所有的標簽,這樣就已經足夠了,讓我們檢查一下吧:
extract_pos(hindi_doc)
毫不意外,詞性分析器很完美地處理了印地語文本。看看這個“????”吧,詞性分析器指出這是個人稱代詞(我、他、她),這還是比較準確的。
調用 CoreNLP 的 API 進行文字分析
CoreNLP 是一個久經考驗的工業級自然語言處理工具集,它的高性能和準確性都是相當有名的。要想調用 CoreNLP 復雜的 API,你只需要在 StanfordNLP 里寫上三行代碼。你沒看錯,確實只需要 3 行代碼就能設置好了!
打開冰箱門 不,是下載 CoreNLP 包。打開你的 Linux 終端,輸入以下命令:
wget http://nlp.stanford.edu/software/stanford-corenlp-full-2018-10-05.zip
解壓下載好的軟件包:
unzip stanford-corenlp-full-2018-10-05.zip
啟動 CoreNLP 服務器:
java -mx4g -cp "*" edu.stanford.nlp.pipeline.StanfordCoreNLPServer -port 9000 -timeout 15000
注意: CoreNLP 需要 Java8 才能運行,請務必確保你已經安裝好了 JDK 和 JRE 1.8.x 以上版本。
接著,你需要讓 StanfordNLP 獲取到 CoreNLP 所在的路徑。你需要把 CoreNLP 的路徑寫入環境變量 $CORENLP_HOME 中。在我上面的例子中,CoreNLP 所在的文件夾是直接放在用戶的 home 目錄中,所以我的環境變量是這樣:
export CORENLP_HOME=stanford-corenlp-full-2018-10-05/
上面的準備工作完成之后,你就可以啟動服務進程,并用 Python 代碼給它發送請求。接下來,我們將啟動服務器,設置客戶端,發送處理請求,并最后從返回的對象中獲取所需的數據。讓我們一起看看這個綜合性的實例吧。
1. 構建一個 CoreNLP 客戶端
# 文件名: corenlp_setup.pyfrom stanfordnlp.server import CoreNLPClient
# 輸入實例文本print('---')
print('input text')
print('')
text = "Chris Manning is a nice person. Chris wrote a simple sentence. He also gives oranges to people."
print(text)
# 顯示服務器啟動信息print('---')
print('starting up Java Stanford CoreNLP Server...')
# 啟動客戶端進程with CoreNLPClient(annotators=['tokenize','ssplit','pos','lemma','ner','depparse','coref'],
timeout=30000, memory='16G') as client:
# 把處理請求發送給服務器 ann = client.annotate(text)
# 獲取返回對象的第 1 個句子 sentence = ann.sentence[0]
2. 依存關系分析及詞性分析
# 文件名: corenlp_depparse.py
# 獲取第 1 個句子的依存關系 print('---')
print('dependency parse of first sentence')
dependency_parse = sentence.basicDependencies
print(dependency_parse)
# 獲取第 1 個句子中的第 1 個詞 print('---')
print('first token of first sentence')
token = sentence.token[0]
print(token)
# 詞性分析結果 print('---')
print('part of speech tag of token')
token.pos
print(token.pos)
3. 命名實體識別(NER)與共指鏈(Co-Reference Chains)的解析
# 文件名: corenlp_ner.py
# 獲取命名實體標簽 print('---')
print('named entity tag of token')
print(token.ner)
# 獲取句子中的第 1 個實體指稱語(entity mention) print('---')
print('first entity mention in sentence')
print(sentence.mentions[0])
# 獲取共指鏈 print('---')
print('coref chains for the example')
print(ann.corefChain)
# 用正則表達式模板查找 wrote 對應的主語 pattern = '([ner: PERSON]+) /wrote/ /an?/ []{0,3} /sentence|article/'
matches = client.tokensregex(text, pattern)
# sentences 中包含了每一條匹配到的句子 assert len(matches["sentences"]) == 3
# 檢查 length 的值,你就知道是否有成功匹配到 assert matches["sentences"][1]["length"] == 1
# 像大部分正則分組一樣,你可以直接獲取匹配到的文字 matches["sentences"][1]["0"]["text"] == "Chris wrote a simple sentence"
matches["sentences"][1]["0"]["1"]["text"] == "Chris"
# 還可以用 semgrex 表達式直接查找結果 pattern = '{word:wrote} >nsubj {}=subject >dobj {}=object'
matches = client.semgrex(text, pattern)
# sentences 中包含了每一條匹配到的句子 assert len(matches["sentences"]) == 3
# 檢查 length 的值,你就知道是否有成功匹配到 assert matches["sentences"][1]["length"] == 1
# 像大部分正則分組一樣,你可以直接獲取匹配到的文字 matches["sentences"][1]["0"]["text"] == "wrote"
matches["sentences"][1]["0"]["$subject"]["text"] == "Chris"
matches["sentences"][1]["0"]["$object"]["text"] == "sentence"
在 Python 中使用 CoreNLP 的時候,我最喜歡的就是它帶來的方便與易用。
個人認為,StanfordNLP? 的優勢與不足之處
考慮到未來的使用前景,StanfordNLP 最讓我興奮的優勢有:
在許多不同的語言分析上,都能做到開箱即用
事實上,它將成為官方的 Python 語言 CoreNLP 接口,這意味著它今后使用會越來越方便,功能也會越來越強大。
雖然內存開銷相當大,但總體來說運算速度非常快。
在 Python 中能方便直觀地運行與調試它。
然而,還是有一些問題需要解決。以下是我對 StanfordNLP 需要改進的地方的看法:
語言模型的下載量略微嫌大了點(雖然已經從原來英文1.9GB/中文1.8GB下降到現在的 244MB / 234MB,但考慮到網絡情況,總的來說還是要花上比較久的時間)。
還是需要大量的代碼來形成可用的功能。比起 NLTK 那種能快速編寫原型腳本的庫來說,StanfordNLP 還有很長的路要走。
目前還缺少可視化功能,而這對依存關系分析還是非常有用的。與 SpaCy 之類的庫相比,StanfordNLP 在這方面還存在著短板。
最后,
結語
就目前來說,類似 CoreNLP 這樣神奇的工具正在積極擁抱 Python 軟件生態系統,斯坦福這樣的科研巨頭也正在努力開源他們的軟件,這讓我對未來抱著樂觀的態度。
確實,StanfordNLP 剛發布 0.2.0 版本不久。雖然這次的版本顯著地縮小了模型大小,加快了速度,但它可改進的空間還很大。再考慮到有斯坦福“官方”加持,它未來一定會更加完善,更加強大。所以,現在正是開始學習使用它的最佳時機——為什么不快人一步,提前掌握這項技能呢?
(本文已投稿給「優達學城」。 原作: Mohd Sanad Zaki Rizvi 編譯:歐剃 轉載請保留此信息)
編譯來源: https://medium.com/analytics-vidhya/introduction-to-stanfordnlp-an-nlp-library-for-53-languages-with-python-code-d7c3efdca118
標簽:Udacity、Translate、Python、Machine-Learning
總結
以上是生活随笔為你收集整理的python nlp包_StanfordNLP,让你在 Python 里一手掌握 53 种自然语言分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python编写的程序大全_Python
- 下一篇: python3 线程隔离_Python并