使用 Python+spaCy 進行簡易天然語言處理

使用 Python+spaCy 進行簡易天然語言處理

簡介

天然語言處理(NLP)是人工智能領域最重要的部分之一。它在許多智能應用中擔任了關鍵的角色,例如聊天機器人、正文提取、多語翻譯以及觀點識別等應用。業界 NLP 相關的公司都意識到了,處理非結構文本數據時,不只要看正確率,還須要注意是否能快速獲得想要的結果。前端

NLP 是一個很寬泛的領域,它包括了文本分類、實體識別、機器翻譯、問答系統、概念識別等子領域。在我最近的一篇文章中,我探討了許多用於實現 NLP 的工具與組件。在那篇文章中,我更多的是在描述NLTK(Natural Language Toolkit)這個偉大的庫。python

在這篇文章中,我會將 spaCy —— 這個如今最強大、最早進的 NLP python 庫分享給大家。react


內容提要

  1. spaCy 簡介及安裝方法
  2. spaCy 的管道與屬性android

    • Tokenization
    • 詞性標註
    • 實體識別
    • 依存句法分析
    • 名詞短語
  3. 集成詞向量計算ios

  4. 使用 spaCy 進行機器學習
  5. 與 NLTK 和 CoreNLP 對比

1. spaCy 簡介及安裝方法

1.1 簡介

spaCy 由 cython(Python 的 C 語言拓展,旨在讓 python 程序達到如同 C 程序同樣的性能)編寫,所以它的運行效率很是高。spaCy 提供了一系列簡潔的 API 方便用戶使用,並基於已經訓練好的機器學習與深度學習模型實現底層。git


1.2 安裝

spaCy 及其數據和模型能夠經過 pip 和安裝工具輕鬆地完成安裝。使用下面的命令在電腦中安裝 spaCy:github

sudo pip install spacy複製代碼

若是你使用的是 Python3,請用 「pip3」 代替 「pip」。web

或者你也能夠在 這兒 下載源碼,解壓後運行下面的命令安裝:算法

python setup.py install複製代碼

在安裝好 spacy 以後,請運行下面的命令如下載全部的數據集和模型:後端

python -m spacy.en.download all複製代碼

一切就緒,如今你能夠自由探索、使用 spacy 了。

2. spaCy 的管道(Pipeline)與屬性(Properties)

spaCy 的使用,以及其各類屬性,是經過建立管道實現的。在加載模型的時候,spaCy 會將管道建立好。在 spaCy 包中,提供了各類各樣的模塊,這些模塊中包含了各類關於詞彙、訓練向量、語法和實體等用於語言處理的信息。

下面,咱們會加載默認的模塊(english-core-web 模塊)。

import spacy
nlp = spacy.load(「en」)複製代碼

「nlp」 對象用於建立 document、得到 linguistic annotation 及其它的 nlp 屬性。首先咱們要建立一個 document,將文本數據加載進管道中。我使用了來自貓途鷹網的旅店評論數據。這個數據文件能夠在這兒下載。

document = unicode(open(filename).read().decode('utf8'))
document = nlp(document)複製代碼

這個 document 如今是 spacy.english 模型的一個 class,並關聯上了許多的屬性。可使用下面的命令列出全部 document(或 token)的屬性:

dir(document)
>> [ 'doc', 'ents', … 'mem']複製代碼

它會輸出 document 中各類各樣的屬性,例如:token、token 的 index、詞性標註、實體、向量、情感、單詞等。下面讓咱們會對其中的一些屬性進行一番探究。

2.1 Tokenization

spaCy 的 document 能夠在 tokenized 過程當中被分割成單句,這些單句還能夠進一步分割成單詞。你能夠經過遍歷文檔來讀取這些單詞:

# document 的首個單詞
document[0]
>> Nice

# document 的最後一個單詞 
document[len(document)-5]
>> boston

# 列出 document 中的句子
list(document.sents)
>> [ Nice place Better than some reviews give it credit for.,
 Overall, the rooms were a bit small but nice.,
...
Everything was clean, the view was wonderful and it is very well located (the Prudential Center makes shopping and eating easy and the T is nearby for jaunts out and about the city).]複製代碼

2.2 詞性標註(POS Tag)

詞性標註即標註語法正確的句子中的詞語的詞性。這些標註能夠用於信息過濾、統計模型,或者基於某些規則進行文本解析。

來看看咱們的 document 中全部的詞性標註:

# 得到全部標註
all_tags = {w.pos: w.pos_ for w in document}
>> {97:  u'SYM', 98: u'VERB', 99: u'X', 101: u'SPACE', 82: u'ADJ', 83: u'ADP', 84: u'ADV', 87: u'CCONJ', 88: u'DET', 89: u'INTJ', 90: u'NOUN', 91: u'NUM', 92: u'PART', 93: u'PRON', 94: u'PROPN', 95: u'PUNCT'}

# document 中第一個句子的詞性標註
for word in list(document.sents)[0]:  
    print word, word.tag_
>> ( Nice, u'JJ') (place, u'NN') (Better, u'NNP') (than, u'IN') (some, u'DT') (reviews, u'NNS') (give, u'VBP') (it, u'PRP') (creit, u'NN') (for, u'IN') (., u'.')複製代碼

來看一看 document 中的最經常使用詞彙。我已經事先寫好了預處理和文本數據清洗的函數。

#一些參數定義
noisy_pos_tags = [「PROP」]
min_token_length = 2

#檢查 token 是否是噪音的函數
def isNoise(token):     
    is_noise = False
    if token.pos_ in noisy_pos_tags:
        is_noise = True
    elif token.is_stop == True:
        is_noise = True
    elif len(token.string) <= min_token_length:
        is_noise = True
    return is_noise
def cleanup(token, lower = True):
    if lower:
       token = token.lower()
    return token.strip()

# 評論中最經常使用的單詞
from collections import Counter
cleaned_list = [cleanup(word.string) for word in document if not isNoise(word)]
Counter(cleaned_list) .most_common(5)
>> [( u'hotel', 683), (u'room', 652), (u'great', 300),  (u'sheraton', 285), (u'location', 271)]複製代碼

2.3 實體識別

spaCy 擁有一個快速實體識別模型,這個實體識別模型可以從 document 中找出實體短語。它能識別各類類型的實體,例如人名、位置、機構、日期、數字等。你能夠經過「.ents」屬性來讀取這些實體。

下面讓咱們來獲取咱們 document 中全部類型的命名實體:

labels = set([w.label_ for w in document.ents])
for label in labels:
    entities = [cleanup(e.string, lower=False) for e in document.ents if label==e.label_]
    entities = list(set(entities))
    print label,entities複製代碼

2.4 依存句法分析

spaCy 最強大的功能之一就是它能夠經過調用輕量級的 API 來實現又快又準確的依存分析。這個分析器也能夠用於句子邊界檢測以及區分短語塊。依存關係能夠經過「.children」、「.root」、「.ancestor」等屬性讀取。

# 取出全部句中包含「hotel」單詞的評論
hotel = [sent for sent in document.sents if 'hotel' in sent.string.lower()]

# 建立依存樹
sentence = hotel[2] for word in sentence:
print word, ': ', str(list(word.children))
>> A :  []  cab :  [A, from]
from :  [airport, to]
the :  []
airport :  [the]
to :  [hotel]
the :  [] hotel :  
[the] can :  []
be :  [cab, can, cheaper, .]
cheaper :  [than] than :  
[shuttles]
the :  []
shuttles :  [the, depending]
depending :  [time] what :  []
time :  [what, of] of :  [day]
the :  [] day :  
[the, go] you :  
[]
go :  [you]
. :  []複製代碼

解析全部居中包含「hotel」單詞的句子的依存關係,並檢查對於 hotel 人們用了哪些形容詞。我建立了一個自定義函數,用於分析依存關係並進行相關的詞性標註。

# 檢查修飾某個單詞的全部形容詞
def pos_words (sentence, token, ptag):
    sentences = [sent for sent in sentence.sents if token in sent.string]     
    pwrds = []
    for sent in sentences:
        for word in sent:
            if character in word.string:
                   pwrds.extend([child.string.strip() for child in word.children
                                                      if child.pos_ == ptag] )
    return Counter(pwrds).most_common(10)

pos_words(document, 'hotel', 「ADJ」)
>> [(u'other', 20), (u'great', 10), (u'good', 7), (u'better', 6), (u'nice', 6), (u'different', 5), (u'many', 5), (u'best', 4), (u'my', 4), (u'wonderful', 3)]複製代碼

2.5 名詞短語(NP)

依存樹也能夠用來生成名詞短語:

# 生成名詞短語
doc = nlp(u'I love data science on analytics vidhya')
for np in doc.noun_chunks:
    print np.text, np.root.dep_, np.root.head.text
>> I nsubj love
   data science dobj love
   analytics pobj on複製代碼

3. 集成詞向量

spaCy 提供了內置整合的向量值算法,這些向量值能夠反映詞中的真正表達信息。它使用 GloVe 來生成向量。GloVe 是一種用於獲取表示單詞的向量的無監督學習算法。

讓咱們建立一些詞向量,而後對其作一些有趣的操做吧:

from numpy import dot
from numpy.linalg import norm
from spacy.en import English
parser = English()

# 生成「apple」的詞向量 
apple = parser.vocab[u'apple']

# 餘弦類似性計算函數
cosine = lambda v1, v2: dot(v1, v2) / (norm(v1) * norm(v2))
others = list({w for w in parser.vocab if w.has_vector and w.orth_.islower() and w.lower_ != unicode("apple")})

# 根據類似性值進行排序
others.sort(key=lambda w: cosine(w.vector, apple.vector))
others.reverse()


print "top most similar words to apple:"
for word in others[:10]:
    print word.orth_
>> apples iphone f ruit juice cherry lemon banana pie mac orange複製代碼

4. 使用 spaCy 對文本進行機器學習

將 spaCy 集成進機器學習模型是很是簡單、直接的。讓咱們使用 sklearn 作一個自定義的文本分類器。咱們將使用 cleaner、tokenizer、vectorizer、classifier 組件來建立一個 sklearn 管道。其中的 tokenizer 和 vectorizer 會使用咱們用 spaCy 自定義的模塊構建。

from sklearn.feature_extraction.stop_words import ENGLISH_STOP_WORDS as stopwords
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics import accuracy_score
from sklearn.base import TransformerMixin
from sklearn.pipeline import Pipeline
from sklearn.svm import LinearSVC

import string
punctuations = string.punctuation

from spacy.en import English
parser = English()

# 使用 spaCy 自定義 transformer
class predictors(TransformerMixin):
    def transform(self, X, **transform_params):
        return [clean_text(text) for text in X]
    def fit(self, X, y=None, **fit_params):
        return self
    def get_params(self, deep=True):
        return {}

# 進行文本清洗的實用的基本函數
def clean_text(text):     
    return text.strip().lower()複製代碼

如今讓咱們使用 spaCy 的解析器和一些基本的數據清洗函數來建立一個自定義的 tokenizer 函數。值得一提的是,你能夠用詞向量來代替文本特徵(使用深度學習模型效果會有較大的提高)

#建立 spaCy tokenizer,解析句子並生成 token
#也能夠用詞向量函數來代替它
def spacy_tokenizer(sentence):
    tokens = parser(sentence)
    tokens = [tok.lemma_.lower().strip() if tok.lemma_ != "-PRON-" else tok.lower_ for tok in tokens]
    tokens = [tok for tok in tokens if (tok not in stopwords and tok not in punctuations)]     return tokens

#建立 vectorizer 對象,生成特徵向量,以此能夠自定義 spaCy 的 tokenizer
vectorizer = CountVectorizer(tokenizer = spacy_tokenizer, ngram_range=(1,1)) classifier = LinearSVC()複製代碼

如今能夠建立管道,加載數據,而後運行分類模型了。

# 建立管道,進行文本清洗、tokenize、向量化、分類操做
pipe = Pipeline([("cleaner", predictors()),
                 ('vectorizer', vectorizer),
                 ('classifier', classifier)])

# Load sample data
train = [('I love this sandwich.', 'pos'),          
         ('this is an amazing place!', 'pos'),
         ('I feel very good about these beers.', 'pos'),
         ('this is my best work.', 'pos'),
         ("what an awesome view", 'pos'),
         ('I do not like this restaurant', 'neg'),
         ('I am tired of this stuff.', 'neg'),
         ("I can't deal with this", 'neg'),
         ('he is my sworn enemy!', 'neg'),          
         ('my boss is horrible.', 'neg')]
test =   [('the beer was good.', 'pos'),     
         ('I do not enjoy my job', 'neg'),
         ("I ain't feelin dandy today.", 'neg'),
         ("I feel amazing!", 'pos'),
         ('Gary is a good friend of mine.', 'pos'),
         ("I can't believe I'm doing this.", 'neg')]

# 建立模型並計算準確率
pipe.fit([x[0] for x in train], [x[1] for x in train])
pred_data = pipe.predict([x[0] for x in test])
for (sample, pred) in zip(test, pred_data):
    print sample, pred
print "Accuracy:", accuracy_score([x[1] for x in test], pred_data)

>>    ('the beer was good.', 'pos') pos
      ('I do not enjoy my job', 'neg') neg
      ("I ain't feelin dandy today.", 'neg') neg
      ('I feel amazing!', 'pos') pos
      ('Gary is a good friend of mine.', 'pos') pos
      ("I can't believe I'm doing this.", 'neg') neg
      Accuracy: 1.0複製代碼

5. 和其它庫的對比

Spacy 是一個很是強大且具有工業級能力的 NLP 包,它能知足大多數 NLP 任務的需求。可能你會思考:爲何會這樣呢?

讓咱們把 Spacy 和另外兩個 python 中有名的實現 NLP 的工具 —— CoreNLP 和 NLTK 進行對比吧!

支持功能表

功能 Spacy NLTK Core NLP
簡易的安裝方式 Y Y Y
Python API Y Y N
多語種支持 N Y Y
分詞 Y Y Y
詞性標註 Y Y Y
分句 Y Y Y
依存性分析 Y N Y
實體識別 Y Y Y
詞向量計算集成 Y N N
情感分析 Y Y Y
共指消解 N N Y

速度:主要功能(Tokenizer、Tagging、Parsing)速度

Tokenizer Tagging Parsing
spaCy 0.2ms 1ms 19ms
CoreNLP 2ms 10ms 49ms
NLTK 4ms 443ms

準確性:實體抽取結果

準確率 Recall F-Score
spaCy 0.72 0.65 0.69
CoreNLP 0.79 0.73 0.76
NLTK 0.51 0.65 0.58

結束語

本文討論了 spaCy —— 這個基於 python,徹底用於實現 NLP 的庫。咱們經過許多用例展現了 spaCy 的可用性、速度及準確性。最後咱們還將其他其它幾個著名的 NLP 庫 —— CoreNLP 與 NLTK 進行了對比。

若是你能真正理解這篇文章要表達的內容,那你必定能夠去實現各類有挑戰的文本數據與 NLP 問題。

但願你能喜歡這篇文章,若是你有疑問、問題或者別的想法,請在評論中留言。

做者介紹:

Shivam Bansal

Shivam Bansal 是一位數據科學家,在 NLP 與機器學習領域有着豐富的經驗。他樂於學習,但願能解決一些富有挑戰性的分析類問題。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOSReact前端後端產品設計 等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃

相關文章
相關標籤/搜索