零、Introduction to Spacy
0.1 nlp对象、toke对象、span对象
如果是处理中文则是导入中文类:from spacy.lang.zh import Chinese,并且创建nlp对象nlp = Chinese()。
(1)这里实例化的对象包含处理管道pipeline,可用于分词,spacy.lang可支持多种语言。
(2)这里我们将文本doc传参入刚才实例化的nlp对象,然后像列表一样进行遍历,也可以通过下标进行索引。
(3)可以通过.text访问文本中每个分词的文本,其可以是一个单词或标点符号。
# -*- coding: utf-8 -*- """ Created on Wed Dec 8 10:16:04 2021 @author: 86493 """ # 导入英文类 from spacy.lang.en import English # 实例化一个nlp类对象,包含管道pipeline nlp = English() # print(nlp) doc = nlp("December is excited!") # 迭代tokens for token in doc: print(token.text) token = doc[1] print(token.text)
December is excited ! is
(1)也可以将多个元素组成Span
对象,如下会打印出is excited
,注意也是左开右闭。
(2)Span
对象只是一个视图,并没有包含数据本身,
# 左开右闭 span = doc[1: 3] print(span.text)
0.2 词汇属性
依次打印出文本中的index、分词、是否为字母、是否为标点符号、是否为数字。
doc = nlp("It costs $5.") print("Index: ", [token.i for token in doc]) print("Text: ", [token.text for token in doc]) print("is_alpha:", [token.is_alpha for token in doc]) print("is_punct:", [token.is_punct for token in doc]) print("like_num:", [token.like_num for token in doc])
结果为:
Index: [0, 1, 2, 3, 4] Text: ['It', 'costs', '$', '5', '.'] is_alpha: [True, True, False, False, False] is_punct: [False, False, False, False, True] like_num: [False, False, False, True, False]
一、统计模型
1.1 依存标注、词性标注
可以完成词性标注、依存关系解析、命名实体识别等任务,是从标注过的文本中训练而来。
$ python -m spacy download en_core_web_sm import spacy nlp = spacy.load("en_core_web_sm")
(1)Part-of-speech Tags词性标注,可以通过token.pos_获得token的词性标注。
(2).dep_属性返回预测的依存关系标注。
(3).head属性返回句法头词符。即词在句子中所依附的母词符。
注意在spaCy中,返回字符串的属性名一般结尾会有下划线;没有下划线的属性会返回一个整型的ID值。
import spacy # Load the small English model nlp = spacy.load("en_core_web_sm") # Process a text doc = nlp("She ate the pizza") # Iterate over the tokens for token in doc: # Print the text and the predicted part-of-speech tag print(token.text, token.pos_, token.dep_, token.head.text)
She PRON nsubj ate ate VERB ROOT ate the DET det pizza pizza NOUN dobj ate
命名实体是那些被赋予了名字的真实世界的物体,比如一个人、一个组织或者一个国家。
1.2 命名实体标注
从doc.ents中可以读取模型预测出的所有命名实体。
(1)它会返回一个Span实例的遍历器,我们可以打印出实体文本和用.label_属性来打印出实体标注。
(2)ents.text为对应识别出的实体。
下面即找出句子中所有的命名实体:
# 处理文本 doc = nlp("微软准备用十亿美金买下这家英国的创业公司。") # 遍历识别出的实体 for ent in doc.ents: # 打印实体文本及其标注 print(ent.text, ent.label_)
模型正确地将"微软"识别为一个组织,将"英国"识别为一个地理政治实体, 将"十亿美金"预测为钱。当然如果不知道GPE
啥意思,可以spacy.explain("GPE")
查看,达到'Countries, cities, states'
的解释。结果为:
微软 ORG 十亿美金 MONEY 英国 GPE
小练习:打印出句子中的的文字、词符的.pos_
(词性标注) 以及词符的.dep_
(依存标注)
import spacy nlp = spacy.load("zh_core_web_sm") text = "写入历史了:苹果是美国第一家市值超过一万亿美元的上市公司。" # 处理文本 doc = nlp(text) for token in doc: # 获取词符文本、词性标注及依存关系标签 token_text = token.text token_pos = token.pos_ token_dep = token.dep_ # 规范化打印的格式 print(f"{token_text:<12}{token_pos:<10}{token_dep:<10}")
写入 VERB ROOT 历史 NOUN dobj 了 PART discourse : PUNCT punct 苹果 NOUN nsubj 是 VERB cop 美国 PROPN nmod 第一 NUM nummod 家 NUM mark:clf 市值 NOUN nsubj 超过 VERB acl 一万亿 NUM nmod:range 美元 NUM mark:clf 的 PART mark 上市 NOUN compound:nn 公司 NOUN ROOT 。 PUNCT punct
(2)命名实体识别
import spacy # Load the small English model nlp = spacy.load("en_core_web_sm") # Process a text doc = nlp("It’s official: Apple is the first U.S. public company to reach a $1 trillion market value") # 命名实体识别 for ent in doc.ents: # 打印实体文本和标签 print(ent.text, ent.label_)
可以看到上面句子对应的实体:
Apple ORG first ORDINAL U.S. GPE $1 trillion MONEY
小测:
二、基于规则的匹配
2.1 不直接用正则表达式的原因
我们是在Doc对象中而不是直接在字符串上做匹配(与正则表达式相比,matcher是配合Doc和Token这样的方法来使用的, 而不是只作用于字符串上。)
我们是在词符及其属性中做匹配
我们可以直接调用模型的预测结果来写规则。
举个例子,“duck” (动词) vs. “duck” (名词)是不一样的("duck"名词意思是鸭子,而动词是闪避的意思)
2.2 匹配的模板 Matcher
匹配的模板是一个列表,列表中每个元素是一个字典。
每个字典即一个字符,字典的key为字符属性名,value为映射到对应的目标值。
(1)注意一开始要传入nlp.vocab词表。
(2)matcher.add方法可以用来添加一个模板。第一个参数是唯一的ID用来识别匹配的是哪一个模板。
【栗子1】匹配词符的完全一致的文字
下面的for循环其实也可以写成print("Matchers:", [doc[start: end].text for match_id, start, end in matches])。
注意:官方教程说是matcher.add("IPHONE_PATTERN", pattern),但是试了下报错(PS:spacy3.0以前的版本很多不太一样的写法),这里应该给pattern加上[ ],参考官方文档的栗子:
# 使用matcher import spacy from spacy.matcher import Matcher # 读取一个模型,创建nlp实例 nlp = spacy.load("en_core_web_sm") # 用模型分享出的volab初始化matcher matcher = Matcher(nlp.vocab) # 给matcher加入模板 pattern = [{"TEXT": "iPhone"}, {"TEXT": "X"}] matcher.add("IPHONE_PATTERN", [pattern]) # 处理文本 doc = nlp("Upcoming iPhone X release date leaked") # 调用matcher matches = matcher(doc) # 遍历所有的匹配结果 for mathc_id, start, end in matches: # 获得匹配的跨度 matched_span = doc[start: end] print(matched_span.text)
对doc调用一个matcher时会返回一个列表,其中列表中每个元素是一个元组tuple。
每个元组由三个值构成:匹配到的ID,匹配到的跨度的起始start和终止索引end。
所以我们可以对所有的匹配结果进行遍历,然后创建Span实例。 这个实例即为doc被起始和终止索引截取的部分。
iPhone X
【栗子2】匹配任意的词符属性
pattern = [ {"LEMMA": "喜欢", "POS": "VERB"}, {"POS": "NOUN"} ] doc = nlp("我喜欢狗但我更喜欢猫。")
词根是“喜欢”的动作,后面接一个名词:
喜欢狗 喜欢猫
【栗子3】使用运算符和量词
可以规定匹配的次数:
pattern = [ {"LEMMA": "买"}, {"POS": "NUM", "OP": "?"}, # 可选: 匹配0次或者1次 {"POS": "NOUN"} ] doc = nlp("我买个肉夹馍。我还要买凉皮。")
在这里"?"运算符使相应的判断词符变为可选, 所以我们会匹配到一个词根为"买"的词符,一个可选的数词和一个名词。
买个肉夹馍 买凉皮
2.3 Matcher小练习
【栗子1】只匹配到所有提及完整iOS版本的部分
doc = nlp( "升级iOS之后,我们并没有发现系统设计有很大的不同,远没有当年iOS 7发布时带来的" "焕然一新的感觉。大部分iOS 11的设计与iOS 10保持一致。但我们仔细试用后也发现了一些" "小的改进。" ) # 写一个模板来匹配完整的iOS版本 ("iOS 7", "iOS 11", "iOS 10") pattern = [{"TEXT": "iOS"}, {"IS_DIGIT": True}]
Match found: iOS 7 Match found: iOS 11 Match found: iOS 10
【栗子2】“下载”+专有名词
doc = nlp( "我之前有去下载Dota到电脑上面,但是根本打不开游戏,怎么办?" "我下载Minecraft,是Windows的版本,下载后是一个'.zip'的文件夹,然后我用了默认软件做了" "解压...我是不是还需要去下载Winzip?" ) # 写一个模板来匹配"下载"加一个代词 pattern = [{"TEXT": "下载"}, {"POS": "PROPN"}]
Match found: 下载Dota Match found: 下载Minecraft Match found: 下载Winzip
【栗子3】形容词后接名词
匹配到形容词(“ADJ”) 后面跟着一两个名词"NOUN"(一个名词和另一个可能有的名词)。
doc = nlp( "这个app的特性包括了优雅设计、快捷搜索、自动标签以及可选声音。" ) # 写一个模板是形容词加上一个或者两个名词 pattern = [{"POS": "ADJ"}, {"POS": "NOUN"}, {"POS": "NOUN", "OP": "?"}]
Match found: 优雅设计 Match found: 快捷搜索 Match found: 自动标签 Match found: 可选声音