当前位置:   article > 正文

使用 Python+spaCy 进行简易自然语言处理

spacy 自定义tokenizer
本文讲的是使用 Python+spaCy 进行简易自然语言处理

使用 Python+spaCy 进行简易自然语言处理

简介

自然语言处理(NLP)是人工智能领域最重要的部分之一。它在许多智能应用中担任了关键的角色,例如聊天机器人、正文提取、多语翻译以及观点识别等应用。业界 NLP 相关的公司都意识到了,处理非结构文本数据时,不仅要看正确率,还需要注意是否能快速得到想要的结果。

NLP 是一个很宽泛的领域,它包括了文本分类、实体识别、机器翻译、问答系统、概念识别等子领域。在我最近的一篇文章中,我探讨了许多用于实现 NLP 的工具与组件。在那篇文章中,我更多的是在描述NLTK(Natural Language Toolkit)这个伟大的库。

在这篇文章中,我会将 spaCy —— 这个现在最强大、最先进的 NLP python 库分享给你们。


内容提要

  1. spaCy 简介及安装方法
  2. spaCy 的管道与属性

    • Tokenization
    • 词性标注
    • 实体识别
    • 依存句法分析
    • 名词短语
  3. 集成词向量计算

  4. 使用 spaCy 进行机器学习
  5. 与 NLTK 和 CoreNLP 对比

1. spaCy 简介及安装方法

1.1 简介

spaCy 由 cython(Python 的 C 语言拓展,旨在让 python 程序达到如同 C 程序一样的性能)编写,因此它的运行效率非常高。spaCy 提供了一系列简洁的 API 方便用户使用,并基于已经训练好的机器学习与深度学习模型实现底层。


1.2 安装

spaCy 及其数据和模型可以通过 pip 和安装工具轻松地完成安装。使用下面的命令在电脑中安装 spaCy:

sudo pip install spacy

如果你使用的是 Python3,请用 “pip3” 代替 “pip”。

或者你也可以在 这儿 下载源码,解压后运行下面的命令安装:

python setup.py install

在安装好 spacy 之后,请运行下面的命令以下载所有的数据集和模型:

python -m spacy.en.download all

一切就绪,现在你可以自由探索、使用 spacy 了。

2. spaCy 的管道(Pipeline)与属性(Properties)

spaCy 的使用,以及其各种属性,是通过创建管道实现的。在加载模型的时候,spaCy 会将管道创建好。在 spaCy 包中,提供了各种各样的模块,这些模块中包含了各种关于词汇、训练向量、语法和实体等用于语言处理的信息。

下面,我们会加载默认的模块(english-core-web 模块)。

  1. import spacy
  2. nlp = spacy.load(“en”)

“nlp” 对象用于创建 document、获得 linguistic annotation 及其它的 nlp 属性。首先我们要创建一个 document,将文本数据加载进管道中。我使用了来自猫途鹰网的旅店评论数据。这个数据文件可以在这儿下载。

  1. document = unicode(open(filename).read().decode('utf8'))
  2. document = nlp(document)

这个 document 现在是 spacy.english 模型的一个 class,并关联上了许多的属性。可以使用下面的命令列出所有 document(或 token)的属性:

  1. dir(document)
  2. >> [ 'doc', 'ents', … 'mem']

它会输出 document 中各种各样的属性,例如:token、token 的 index、词性标注、实体、向量、情感、单词等。下面让我们会对其中的一些属性进行一番探究。

2.1 Tokenization

spaCy 的 document 可以在 tokenized 过程中被分割成单句,这些单句还可以进一步分割成单词。你可以通过遍历文档来读取这些单词:

  1. # document 的首个单词
  2. document[0]
  3. >> Nice
  4. # document 的最后一个单词
  5. document[len(document)-5]
  6. >> boston
  7. # 列出 document 中的句子
  8. list(document.sents)
  9. >> [ Nice place Better than some reviews give it credit for.,
  10. Overall, the rooms were a bit small but nice.,
  11. ...
  12. 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 中所有的词性标注:

  1. # 获得所有标注
  2. all_tags = {w.pos: w.pos_ for w in document}
  3. >> {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'}
  4. # document 中第一个句子的词性标注
  5. for word in list(document.sents)[0]:
  6. print word, word.tag_
  7. >> ( 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 中的最常用词汇。我已经事先写好了预处理和文本数据清洗的函数。

  1. #一些参数定义
  2. noisy_pos_tags = [“PROP”]
  3. min_token_length = 2
  4. #检查 token 是不是噪音的函数
  5. def isNoise(token):
  6. is_noise = False
  7. if token.pos_ in noisy_pos_tags:
  8. is_noise = True
  9. elif token.is_stop == True:
  10. is_noise = True
  11. elif len(token.string) <= min_token_length:
  12. is_noise = True
  13. return is_noise
  14. def cleanup(token, lower = True):
  15. if lower:
  16. token = token.lower()
  17. return token.strip()
  18. # 评论中最常用的单词
  19. from collections import Counter
  20. cleaned_list = [cleanup(word.string) for word in document if not isNoise(word)]
  21. Counter(cleaned_list) .most_common(5)
  22. >> [( u'hotel', 683), (u'room', 652), (u'great', 300), (u'sheraton', 285), (u'location', 271)]

2.3 实体识别

spaCy 拥有一个快速实体识别模型,这个实体识别模型能够从 document 中找出实体短语。它能识别各种类型的实体,例如人名、位置、机构、日期、数字等。你可以通过“.ents”属性来读取这些实体。

下面让我们来获取我们 document 中所有类型的命名实体:

  1. labels = set([w.label_ for w in document.ents])
  2. for label in labels:
  3. entities = [cleanup(e.string, lower=False) for e in document.ents if label==e.label_]
  4. entities = list(set(entities))
  5. print label,entities

2.4 依存句法分析

spaCy 最强大的功能之一就是它可以通过调用轻量级的 API 来实现又快又准确的依存分析。这个分析器也可以用于句子边界检测以及区分短语块。依存关系可以通过“.children”、“.root”、“.ancestor”等属性读取。

  1. # 取出所有句中包含“hotel”单词的评论
  2. hotel = [sent for sent in document.sents if 'hotel' in sent.string.lower()]
  3. # 创建依存树
  4. sentence = hotel[2] for word in sentence:
  5. print word, ': ', str(list(word.children))
  6. >> A : [] cab : [A, from]
  7. from : [airport, to]
  8. the : []
  9. airport : [the]
  10. to : [hotel]
  11. the : [] hotel :
  12. [the] can : []
  13. be : [cab, can, cheaper, .]
  14. cheaper : [than] than :
  15. [shuttles]
  16. the : []
  17. shuttles : [the, depending]
  18. depending : [time] what : []
  19. time : [what, of] of : [day]
  20. the : [] day :
  21. [the, go] you :
  22. []
  23. go : [you]
  24. . : []

解析所有居中包含“hotel”单词的句子的依存关系,并检查对于 hotel 人们用了哪些形容词。我创建了一个自定义函数,用于分析依存关系并进行相关的词性标注。

  1. # 检查修饰某个单词的所有形容词
  2. def pos_words (sentence, token, ptag):
  3. sentences = [sent for sent in sentence.sents if token in sent.string]
  4. pwrds = []
  5. for sent in sentences:
  6. for word in sent:
  7. if character in word.string:
  8. pwrds.extend([child.string.strip() for child in word.children
  9. if child.pos_ == ptag] )
  10. return Counter(pwrds).most_common(10)
  11. pos_words(document, 'hotel', “ADJ”)
  12. >> [(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)

依存树也可以用来生成名词短语:

  1. # 生成名词短语
  2. doc = nlp(u'I love data science on analytics vidhya')
  3. for np in doc.noun_chunks:
  4. print np.text, np.root.dep_, np.root.head.text
  5. >> I nsubj love
  6. data science dobj love
  7. analytics pobj on

3. 集成词向量

spaCy 提供了内置整合的向量值算法,这些向量值可以反映词中的真正表达信息。它使用GloVe 来生成向量。GloVe 是一种用于获取表示单词的向量的无监督学习算法。

让我们创建一些词向量,然后对其做一些有趣的操作吧:

  1. from numpy import dot
  2. from numpy.linalg import norm
  3. from spacy.en import English
  4. parser = English()
  5. # 生成“apple”的词向量
  6. apple = parser.vocab[u'apple']
  7. # 余弦相似性计算函数
  8. cosine = lambda v1, v2: dot(v1, v2) / (norm(v1) * norm(v2))
  9. others = list({w for w in parser.vocab if w.has_vector and w.orth_.islower() and w.lower_ != unicode("apple")})
  10. # 根据相似性值进行排序
  11. others.sort(key=lambda w: cosine(w.vector, apple.vector))
  12. others.reverse()
  13. print "top most similar words to apple:"
  14. for word in others[:10]:
  15. print word.orth_
  16. >> apples iphone f ruit juice cherry lemon banana pie mac orange

4. 使用 spaCy 对文本进行机器学习

将 spaCy 集成进机器学习模型是非常简单、直接的。让我们使用 sklearn 做一个自定义的文本分类器。我们将使用 cleaner、tokenizer、vectorizer、classifier 组件来创建一个 sklearn 管道。其中的 tokenizer 和 vectorizer 会使用我们用 spaCy 自定义的模块构建。

  1. from sklearn.feature_extraction.stop_words import ENGLISH_STOP_WORDS as stopwords
  2. from sklearn.feature_extraction.text import CountVectorizer
  3. from sklearn.metrics import accuracy_score
  4. from sklearn.base import TransformerMixin
  5. from sklearn.pipeline import Pipeline
  6. from sklearn.svm import LinearSVC
  7. import string
  8. punctuations = string.punctuation
  9. from spacy.en import English
  10. parser = English()
  11. # 使用 spaCy 自定义 transformer
  12. class predictors(TransformerMixin):
  13. def transform(self, X, **transform_params):
  14. return [clean_text(text) for text in X]
  15. def fit(self, X, y=None, **fit_params):
  16. return self
  17. def get_params(self, deep=True):
  18. return {}
  19. # 进行文本清洗的实用的基本函数
  20. def clean_text(text):
  21. return text.strip().lower()

现在让我们使用 spaCy 的解析器和一些基本的数据清洗函数来创建一个自定义的 tokenizer 函数。值得一提的是,你可以用词向量来代替文本特征(使用深度学习模型效果会有较大的提升)

  1. #创建 spaCy tokenizer,解析句子并生成 token
  2. #也可以用词向量函数来代替它
  3. def spacy_tokenizer(sentence):
  4. tokens = parser(sentence)
  5. tokens = [tok.lemma_.lower().strip() if tok.lemma_ != "-PRON-" else tok.lower_ for tok in tokens]
  6. tokens = [tok for tok in tokens if (tok not in stopwords and tok not in punctuations)] return tokens
  7. #创建 vectorizer 对象,生成特征向量,以此可以自定义 spaCy 的 tokenizer
  8. vectorizer = CountVectorizer(tokenizer = spacy_tokenizer, ngram_range=(1,1)) classifier = LinearSVC()

现在可以创建管道,加载数据,然后运行分类模型了。

  1. # 创建管道,进行文本清洗、tokenize、向量化、分类操作
  2. pipe = Pipeline([("cleaner", predictors()),
  3. ('vectorizer', vectorizer),
  4. ('classifier', classifier)])
  5. # Load sample data
  6. train = [('I love this sandwich.', 'pos'),
  7. ('this is an amazing place!', 'pos'),
  8. ('I feel very good about these beers.', 'pos'),
  9. ('this is my best work.', 'pos'),
  10. ("what an awesome view", 'pos'),
  11. ('I do not like this restaurant', 'neg'),
  12. ('I am tired of this stuff.', 'neg'),
  13. ("I can't deal with this", 'neg'),
  14. ('he is my sworn enemy!', 'neg'),
  15. ('my boss is horrible.', 'neg')]
  16. test = [('the beer was good.', 'pos'),
  17. ('I do not enjoy my job', 'neg'),
  18. ("I ain't feelin dandy today.", 'neg'),
  19. ("I feel amazing!", 'pos'),
  20. ('Gary is a good friend of mine.', 'pos'),
  21. ("I can't believe I'm doing this.", 'neg')]
  22. # 创建模型并计算准确率
  23. pipe.fit([x[0] for x in train], [x[1] for x in train])
  24. pred_data = pipe.predict([x[0] for x in test])
  25. for (sample, pred) in zip(test, pred_data):
  26. print sample, pred
  27. print "Accuracy:", accuracy_score([x[1] for x in test], pred_data)
  28. >> ('the beer was good.', 'pos') pos
  29. ('I do not enjoy my job', 'neg') neg
  30. ("I ain't feelin dandy today.", 'neg') neg
  31. ('I feel amazing!', 'pos') pos
  32. ('Gary is a good friend of mine.', 'pos') pos
  33. ("I can't believe I'm doing this.", 'neg') neg
  34. Accuracy: 1.0

5. 和其它库的对比

Spacy 是一个非常强大且具备工业级能力的 NLP 包,它能满足大多数 NLP 任务的需求。可能你会思考:为什么会这样呢?

让我们把 Spacy 和另外两个 python 中有名的实现 NLP 的工具 —— CoreNLP 和 NLTK 进行对比吧!

支持功能表

功能SpacyNLTKCore NLP
简易的安装方式YYY
Python APIYYN
多语种支持NYY
分词YYY
词性标注YYY
分句YYY
依存性分析YNY
实体识别YYY
词向量计算集成YNN
情感分析YYY
共指消解NNY

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

TokenizerTaggingParsing
spaCy0.2ms1ms19ms
CoreNLP2ms10ms49ms
NLTK4ms443ms

准确性:实体抽取结果

准确率RecallF-Score
spaCy0.720.650.69
CoreNLP0.790.730.76
NLTK0.510.650.58

结束语

本文讨论了 spaCy —— 这个基于 python,完全用于实现 NLP 的库。我们通过许多用例展示了 spaCy 的可用性、速度及准确性。最后我们还将其余其它几个著名的 NLP 库 —— CoreNLP 与 NLTK 进行了对比。

如果你能真正理解这篇文章要表达的内容,那你一定可以去实现各种有挑战的文本数据与 NLP 问题。

希望你能喜欢这篇文章,如果你有疑问、问题或者别的想法,请在评论中留言。





原文发布时间为:2017年7月21日

本文来自云栖社区合作伙伴掘金,了解相关信息可以关注掘金网站。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/694252
推荐阅读
相关标签
  

闽ICP备14008679号