SpaCy官方中文教程:一文详解SpaCy的所有功能

前言

​智能处理原始文本困难的原因:

  • “大多数单词出现的频率都很低” :在实际的文本中,有很多单词可能只会出现几次,这就给处理带来了挑战,因为模型很难从有限的出现次数中去学习这些单词的特征和用法。
  • “不同单词即便看起来差别很大,意思却常常差不多” :比如“car”(汽车)和“automobile”(汽车),拼写差异明显但意思相同。这会让基于单词匹配等简单方法的处理变得复杂,因为不能仅仅依靠单词的表面形式来判断其含义。
  • “同样的单词,顺序一变,意思可能就完全不同了” :像 “The dog bites the man”(狗咬人)和 “The man bites the dog”(人咬狗),单词一样但顺序不同,表达的是完全不同的场景和语义。
  • “在很多语言里,就算只是把文本拆分成有用的、类似单词的小单元,也不是件容易事儿” :有些语言没有明显的单词分隔符(如中文),还有些语言存在各种词形变化等情况,使得准确划分出有意义的单元颇具难度。

​借助语言学知识的好处:

  • 仅依靠原始字符处理文本,可能只能做一些很基础的操作,比如简单的字符匹配等。而利用语言学知识,比如词汇的词性、语法结构、语义角色等,可以为文本添加更多有价值的信息,从而更准确地理解和分析文本。

​spaCy的作用:

  • spaCy这个工具的设计目的就是帮助用户更方便地处理文本。用户把原始文本输入进去后,它会返回一个Doc对象,这个对象就像是装满了各种关于文本信息的“宝藏盒”,里面的“注释信息”可以包括每个单词的词性标注、命名实体识别结果、依存句法分析结果等等,这些信息能帮助我们更好地理解和分析文本内容 。

在这里插入图片描述

一、词性标注(Part-of-speech tagging )

spaCy词性标注解释

在完成分词之后,spaCy能够解析并标注给定的文档(Doc)。这一过程依赖于训练好的管道及其统计模型,这些模型使spaCy能够在特定上下文中预测最有可能适用的标签或标记。一个训练好的组件包含二进制数据,这些数据通过向系统展示足够多的例子生成,从而使系统能够对整个语言做出泛化的预测。例如,在英语中,紧跟“the”之后的词很可能是名词。

语言学注解作为Token属性是可用的。与许多自然语言处理库一样,为了减少内存使用和提高效率,spaCy将所有字符串编码为哈希值。因此,要获取属性的可读字符串表示,我们需要在其名称后添加一个下划线(_)。例如,如果你想获取某个token的实际文本内容而不是它的哈希值,你应该使用token.text_

这种机制不仅提高了处理速度,也使得spaCy在执行复杂的自然语言处理任务时更加高效。通过这种方式,开发者可以更容易地访问和理解文本中的语法结构和词语角色。

import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("Apple is looking at buying U.K. startup for $1 billion")

for token in doc:
    print(token.text, token.lemma_, token.pos_, token.tag_, token.dep_,
            token.shape_, token.is_alpha, token.is_stop)

这个循环遍历了doc中的每一个Token(即句子中的每一个单词或符号),并打印出以下属性:
token.text: 单词的原始形式。
token.lemma_: 单词的标准形式(词形还原)。
token.pos_: 简单的词性标注(如名词、动词等)。
token.tag_: 细粒度的词性标注(提供更详细的词性信息)。
token.dep_: 依存关系标签,描述该单词在句子中的语法角色。
token.shape_: 单词的形状模式,例如大写字母、数字等的格式化表示。
token.is_alpha: 布尔值,指示该单词是否完全由字母组成。
token.is_stop: 布尔值,指示该单词是否是停用词(如“is”、“the”等常见但通常不携带重要语义信息的词)。

在这里插入图片描述
使用 spaCy 的内置displaCy 可视化工具,我们的例句及其依赖项如下所示:

在这里插入图片描述

有关 spaCy 模型在不同语言中分配的细粒度和粗粒度词性标记的列表,请参阅模型目录中记录的标签方案(Label Scheme)。

在这里插入图片描述

(1)token.tag_: 细粒度的词性标注

更多示例和说明请查看:https://spacy.io/models/zh#zh_core_web_trf

下面是zh_core_web_trf 模型词性标注的tag_的值,如下

AD: 副词(Adverb)
AS: 介词(Auxiliary)
BA: 把字结构中的“把”(Ba)
CC: 并列连词(Coordinating Conjunction)
CD: 基数词(Cardinal Number)
CS: 从句连词(Clause-Spanning Conjunction)
DEC: 名词化后缀(Deictic Nominalizer)
DEG: 属格标记(Genitive Marker)
DER: 关系从句标记(Relative Clause Marker)
DEV: 动词前缀(Verb Prefix)
DT: 限定词(Determiner)
ETC: 等等(Et cetera)
FW: 外来词(Foreign Word)
IJ: 插入语(Interjection)
INF: 不定式标记(Infinitive Marker)
JJ: 形容词(Adjective)
LB: 被字结构中的“被”(Bei)
LC: 分类词/量词(Classifier)
M: 数量短语中的数量词(Measure Word)
MSP: 助词(助词,可能包括结构助词、动态助词等)
NN: 普通名词(Noun, Singular or Mass)
NR: 专有名词(Noun, Proper Noun)
NT: 时间名词(Noun, Temporal)
OD: 序数词(Ordinal Number)
ON: 方位名词(Noun, Locative)
P: 介词(Preposition)
PN: 代词(Pronoun)
PU: 标点符号(Punctuation)
SB: 主语标记(Subject Marker)
SP: 补语标记(Complement Marker)
URL: 网址(Uniform Resource Locator)
VA: 系动词(Linking Verb)
VC: 动词补语(Verb Complement)
VE: 存现动词(Existential Verb)
VV: 动词(Verb, General)
X: 其他(Other)

(2) token.dep_: 依存关系标签

下面是zh_core_web_trf 模型依存关系dep_标签的值,如下

ROOT: 根节点,表示整个句子的核心动词或主要谓语。
acl: 从句修饰名词(Adnominal Clause),例如定语从句。
advcl:loc: 副词性从句中的地点状语(Adverbial Clause of Location)。
advmod: 副词修饰(Adverbial Modifier),表示副词对其他成分的修饰作用。
advmod:dvp: 动补结构中的副词修饰(Adverbial Modifier in Deverbal Phrase)。
advmod:loc: 地点状语(Locative Adverbial Modifier)。
advmod:rcomp: 结果补语中的副词修饰(Resultative Complement Adverbial Modifier)。
amod: 形容词修饰(Adjectival Modifier),形容词对名词的修饰。
amod:ordmod: 序数修饰(Ordinal Modifier),如“第一”、“第二”等序数词。
appos: 同位语(Appositional Modifier),用于解释或补充前面的名词。
aux:asp: 助词-体标记(Aspect Marker),如“了”、“着”、“过”。
aux:ba: 助词-把字结构(Ba Construction Marker),“把”字句中的助词。
aux:modal: 助词-情态标记(Modal Auxiliary),如“能”、“会”、“应该”等情态动词。
aux:prtmod: 助词-补语标记(Complement Marker),通常用于动补结构。
auxpass: 被动助词(Passive Auxiliary),如“被”字句中的助词。
case: 格标记(Case Marker),如“的”、“地”、“得”等。
cc: 并列连词(Coordinating Conjunction),连接并列成分。
ccomp: 宾语从句(Clause as Complement),如“说”、“认为”等动词后的宾语从句。
compound:nn: 名词复合词(Noun Compound),两个或多个名词构成的复合词。
compound:vc: 动词复合词(Verb Compound),两个或多个动词构成的复合词。
conj: 并列成分(Conjunct),并列结构中的成分。
cop: 系动词(Copula),如“是”、“为”等系动词。
dep: 依赖关系(Dependent),未分类的依赖关系。
det: 限定词(Determiner),如“这”、“那”、“一些”等。
discourse: 话语标记(Discourse Marker),如“嗯”、“啊”等口语标记。
dobj: 直接宾语(Direct Object),直接跟在动词后的宾语。
etc: 等等(Et cetera),表示列举未尽的部分。
mark: 从句标记(Marker),引导从句的标记词。
mark:clf: 数量短语中的分类词(Classifier in Quantifier Phrase)。
name: 专有名词(Name),如人名、地名等。
neg: 否定词(Negation),如“不”、“没”等否定词。
nmod: 名词修饰(Nominal Modifier),名词对名词的修饰。
nmod:assmod: 关联名词修饰(Associative Nominal Modifier),如“的”字短语。
nmod:poss: 所有格(Possessive Modifier),表示所属关系。
nmod:prep: 介词短语中的名词修饰(Prepositional Phrase Nominal Modifier)。
nmod:range: 范围修饰(Range Modifier),表示范围。
nmod:tmod: 时间名词修饰(Temporal Nominal Modifier),表示时间。
nmod:topic: 主题名词修饰(Topic Nominal Modifier),表示话题。
nsubj: 名词性主语(Nominal Subject),作为句子主语的名词。
nsubj:xsubj: 交叉主语(Cross Subject),用于处理复杂句中的主语关系。
nsubjpass: 被动名词性主语(Passive Nominal Subject),被动句中的主语。
nummod: 数量修饰(Numeric Modifier),数字对名词的修饰。
parataxis:prnmod: 并列句中的代词修饰(Paratactic Pronominal Modifier),并列句中的代词修饰关系。
punct: 标点符号(Punctuation),句子中的标点符号。
xcomp: 补语从句(Open Clausal Complement),如“希望你来”的“你来”。

(3)实体命名标签

在spaCy中,实体命名识别(Named Entity Recognition, NER)用于识别文本中的特定类型实体。以下是是中文NER标签值及其解释:

  1. CARDINAL:基数词(Cardinal Number)

    • 表示数量的数字,例如“一”、“一百”、“五千六百七十八”。
  2. DATE:日期(Date)

    • 表示具体的日期或时间段,例如“2023年3月15日”、“明天”、“下周”、“夏季”。
  3. EVENT:事件(Event)

    • 特定的事件名称,例如“奥运会”、“世界杯”、“春节联欢晚会”。
  4. FAC:设施(Facility)

    • 人工建造的结构或场所,例如“机场”、“医院”、“博物馆”。
  5. GPE:地理政治实体(Geopolitical Entity)

    • 国家、城市或其他具有政治意义的地理位置,例如“中国”、“纽约市”、“欧盟”。
  6. LANGUAGE:语言(Language)

    • 语言名称,例如“汉语”、“英语”、“法语”。
  7. LAW:法律(Law)

    • 法律文件或法规的名称,例如“宪法”、“刑法”、“民法典”。
  8. LOC:地点(Location)

    • 自然地点或地理区域,例如“长江”、“喜马拉雅山”、“撒哈拉沙漠”。
  9. MONEY:货币(Money)

    • 货币金额,包括符号和单位,例如“$100”、“人民币五元”、“欧元”。
  10. NORP:民族、宗教或政治团体(Nationalities or Religious or Political Groups)

    • 民族、宗教或政治团体名称,例如“汉族”、“佛教”、“民主党”。
  11. ORDINAL:序数词(Ordinal Number)

    • 表示顺序的词语,例如“第一”、“第二”、“第三”。
  12. ORG:组织(Organization)

    • 公司、机构或其他组织的名称,例如“阿里巴巴”、“联合国”、“北京大学”。
  13. PERCENT:百分比(Percent)

    • 百分比表示,例如“百分之五十”、“50%”。
  14. PERSON:人名(Person)

    • 个人的名字,例如“李华”、“王小明”、“张三”。
  15. PRODUCT:产品(Product)

    • 商品或产品的名称,例如“iPhone”、“华为手机”、“可口可乐”。
  16. QUANTITY:数量(Quantity)

    • 数量描述,包括度量单位,例如“两米”、“五公斤”、“三十摄氏度”。
  17. TIME:时间(Time)

    • 具体的时间点或时间段,例如“三点钟”、“下午两点”、“午夜”。
  18. WORK_OF_ART:艺术作品(Work of Art)

    • 文学、音乐、电影等艺术作品的名称,例如“红楼梦”、“哈利·波特”、“泰坦尼克号”。

示例

假设我们有以下句子,并使用spaCy进行实体识别:

import spacy

nlp = spapy.load("zh_core_web_sm")
doc = nlp("2023年9月,李华在北京大学学习,他计划去法国参加国际会议。")

for ent in doc.ents:
    print(ent.text, ent.label_)

输出可能如下:

2023年9月 DATE
李华 PERSON
北京大学 ORG
法国 GPE
国际会议 EVENT

二、词缀形态(Morphology)

语言学中的词形变化,特别是屈折词缀变化(Inflectional Morphology)。屈折词缀变化指的是通过给词的根形式(即词的基本形式或原型,称为“引理”lemma)添加前缀或后缀来改变其语法功能的过程,但这一过程不会改变该词的词性。

具体来说,一个词的“引理”(也称为词干或基础形式)是该词最原始的形式,不带任何语法标记。当我们在引理上加上特定的词缀(通常是后缀),可以表示不同的时态、数(单数或复数)、人称、性别等语法特征,从而生成所谓的“表面形式”。这个表面形式是实际在句子中使用的词的形式。例如:

  • run (动词原形) 变为 runs(第三人称单数现在时)
  • child (名词单数) 变为 children(名词复数)

这些例子展示了如何通过对基本词汇形式应用屈折变化来表达更具体的语法意义,而不需要改变词的基础含义或其词性。在自然语言处理(NLP)中,理解这些规则对于解析文本和准确识别词汇的角色至关重要,SpaCy等工具能够自动进行这样的分析。

在这里插入图片描述

在语言学和自然语言处理(NLP)中,VerbForm=Fin, Mood=Ind, Tense=Pres 这样的标注是用来描述动词的形式、语气和时态的。

  1. VerbForm=Fin:这里的 “Fin” 是 “Finite” 的缩写,指的是限定形式的动词。限定动词是指那些根据主语的人称和数的变化而变化的动词形式,它们在句子中通常作为谓语,表明动作的发生。例如,在句子 “She runs fast.” 中,“runs” 就是一个有限动词。

  2. Mood=Ind:这里的 “Ind” 代表 “Indicative”(陈述语气)。陈述语气用于表达事实或被认为是真的陈述,是最常见的动词语气。它用来描述现实中的情况、行为或状态。例如:“He goes to school every day.” 在这个例子中,“goes” 使用的是陈述语气,表示一个日常发生的事实。

  3. Tense=Pres:这里的 “Pres” 表示现在时(Present Tense)。现在时用来描述当前时间发生的事情或持续的状态。例如:“They play football in the park.” 这里的 “play” 是现在时态,表示目前正在进行的动作或习惯性行为。

VerbForm=Fin, Mood=Ind, Tense=Pres 描述了一个动词的具体形态,指该动词是有限形式的,以陈述语气呈现,并且使用现在时态。这种标注常见于依赖语法分析的NLP任务中,如句法解析、信息提取等,有助于理解和处理文本内容。例如,在使用SpaCy进行文本分析时,这样的标注可以帮助更精确地理解句子结构和含义。

import spacy

nlp = spacy.load("en_core_web_sm")
print("Pipeline:", nlp.pipe_names)  # ['tok2vec', 'tagger', 'parser', 'attribute_ruler', 'lemmatizer', 'ner']
doc = nlp("I was reading the paper.")
token = doc[0]  # 'I'
print(token.morph)  # 'Case=Nom|Number=Sing|Person=1|PronType=Prs'
print(token.morph.get("PronType"))  # ['Prs']

1. Statistical morphology

spaCy 的Statistical Morphologizer 组件将词缀形态和粗粒度的词性标记分配为Token.morph 和Token.pos 。

import spacy

nlp = spacy.load("de_core_news_sm")
doc = nlp("Wo bist du?") # English: 'Where are you?'
print(doc[2].morph)  # 'Case=Nom|Number=Sing|Person=2|PronType=Prs'
print(doc[2].pos_) # 'PRON'

2. 基于规则的形态学(Rule-based Morphology)

  1. 简单形态系统的语言:对于像英语这样的语言,其形态系统相对简单,即词形变化(如动词时态、名词单复数等)并不复杂。SpaCy通过一种基于规则的方法来分配形态特征。

  2. 细粒度词性标注(Fine-grained Part-of-Speech Tagging)

    • SpaCy首先使用一个词性标注器(POS Tagger)为每个单词分配一个细粒度的词性标签(Token.tag)。这些标签不仅指明了词的基本词性(如名词、动词),还包含了一定量的形态信息。
  3. 粗粒度词性标注和形态特征(Coarse-grained POS Tags and Morphological Features)

    • 对于那些在先前过程中未设置粗粒度词性(coarse-grained POS)的词语,SpaCy使用一个映射表将细粒度的标签转换为粗粒度的词性和形态特征。
    • 这种映射过程帮助从详细的词性信息中提取出更高层次的抽象信息,使分析更加简洁和易于理解。
import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("Where are you?")
print(doc[2].morph)  # 'Case=Nom|Person=2|PronType=Prs'
print(doc[2].pos_)  # 'PRON'

三、词性还原 Lemmatization

SpaCy提供的两种用于词形还原(lemmatization)的管道组件(pipeline components)。词形还原是将单词的不同形式转换为其基本形式或词元(lemma)的过程。这对于自然语言处理任务非常重要,因为它可以帮助减少词汇的多样性,并使分析更加准确和有效。以下是详细解释:

  1. Lemmatizer 组件
  • Lookup 和 Rule-based 方法:这个组件提供了基于查找表(lookup)和基于规则(rule-based)的词形还原方法。

    • Lookup:通过预先定义好的词典或查找表来确定一个词的基本形式。例如,“running”的词元是“run”,这种对应关系存储在一个查找表中。
    • Rule-based:根据预定义的语法规则进行词形还原。例如,对于英语动词,可以通过去掉常见的后缀(如“-ed”、“-ing”等)来找到其基本形式。
  • 可配置性:这个组件是可配置的,意味着不同的语言可以根据需要扩展和定制其词形还原逻辑。每个语言可以定义自己的词形还原规则和查找表作为其语言数据的一部分。

  1. EditTreeLemmatizer v3.3 组件
  • 可训练的词形还原器:这是从SpaCy版本3.3开始引入的一个新的词形还原组件。与基于查找表和规则的方法不同,这个组件是可训练的。
    • 训练模型:它使用机器学习模型来学习如何将单词的不同形式映射到其基本形式。这种方法的优点是可以适应更多样化的输入,并且在某些情况下比固定的规则更灵活和准确。
    • Edit Trees:该组件利用编辑树(edit trees),这是一种表示字符串之间编辑操作的数据结构,帮助模型理解如何将一个词的形式转换为其词元。
import spacy

# English pipelines include a rule-based lemmatizer
nlp = spacy.load("en_core_web_sm")
lemmatizer = nlp.get_pipe("lemmatizer")
print(lemmatizer.mode)  # 'rule'

doc = nlp("I was reading the paper.")
print([token.lemma_ for token in doc])
# ['I', 'be', 'read', 'the', 'paper', '.']

SpaCy v3.0 中的变化

  1. 默认不提供词元

    • 在SpaCy v2中,模型默认会提供词元(lemmas),并且可以根据是否存在词性标注器(tagger)自动切换使用查找表(lookup)或基于规则(rule-based)的词形还原方法。
    • SpaCy v3改变了这一行为:模型不再默认提供词元,也不再自动切换不同的词形还原方法。
  2. 需要显式添加Lemmatizer组件

    • 为了在Doc对象中包含词元信息,必须在处理管道(pipeline)中显式添加一个Lemmatizer组件。
    • Lemmatizer组件的配置:该组件在初始化时需要指定一种模式,如“lookup”(查找表)或“rule”(基于规则)。这意味着你需要明确选择如何进行词形还原。
  3. "rule"模式的要求

    • 如果选择使用“rule”模式,要求单词的Token.pos(词性)必须由之前的组件设置好。这是因为基于规则的词形还原依赖于准确的词性信息来决定如何还原词形。

数据分布与安装

  1. 数据包

    • SpaCy的词形还原所需的数据分布在名为spacy-lookups-data的独立包中。
    • 预训练模型:提供的预训练模型已经包含了所有必要的查找表,因此如果你使用的是这些预训练模型,通常不需要额外操作。
  2. 自定义管道

    • 如果你在创建新的处理管道而不是使用预训练模型,你可能需要手动安装spacy-lookups-data包,以确保在初始化Lemmatizer组件时能够访问所需的查找表数据。

1. Lookup Lemmatizer(查找词形还原器)

在SpaCy中,Lookup Lemmatizer 是一种简单而直接的词形还原方法。它特别适用于那些没有词性标注器(tagger)或形态分析器(morphologizer)的处理管道。以下是详细解释:

工作原理

  1. 基于查找表的词形还原

    • 查找表:Lookup Lemmatizer依赖于一个预先定义好的查找表(lookup table)。这个查找表包含了大量的单词及其对应的词元(lemma)形式。
    • 查找过程:当处理文本时,Lookup Lemmatizer会根据单词的表面形式(surface form)在查找表中进行查找,以找到该单词的词元。
  2. 不依赖词性或上下文

    • 独立性:Lookup Lemmatizer在查找过程中不会参考单词的词性(part-of-speech, POS)或上下文信息。它仅依赖于单词的表面形式来进行词形还原。
    • 简单高效:这种方法的优点是实现简单且高效,因为它不需要复杂的语法分析或上下文理解。

使用场景

  • 无词性标注器的情况:对于那些不需要或无法使用词性标注器的处理管道,Lookup Lemmatizer是一个理想的选择。例如,在一些轻量级的应用中,或者当你只需要基本的词形还原功能时。

  • 数据准备:为了使用Lookup Lemmatizer,你需要提供一个查找表。通常情况下,这个查找表可以通过安装spacy-lookups-data包来获取。这个包包含了多种语言的常见词汇及其词元信息。

示例流程

  1. 安装spacy-lookups-data

    pip install spacy-lookups-data
    
  2. 添加Lookup Lemmatizer到处理管道
    在你的SpaCy处理管道中显式添加Lookup Lemmatizer组件。以下是一个简单的示例代码:

    import spacy
    from spacy.lang.en import English
    from spacy.lookups import Lookups
    
    # 创建一个空的英语nlp对象
    nlp = English()
    
    # 加载查找表数据
    lookups = Lookups()
    lookups.from_disk("/path/to/lookups-data")  # 替换为实际路径
    
    # 添加Lookup Lemmatizer到管道
    lemmatizer = nlp.add_pipe("lemmatizer", config={"mode": "lookup"})
    lemmatizer.lookups = lookups
    
    # 测试
    doc = nlp("running runs ran")
    for token in doc:
        print(token.text, token.lemma_)
    

注意事项

  • 覆盖范围:查找表的覆盖范围有限,可能无法涵盖所有词汇,特别是专有名词、新词或外来词等。因此,在实际应用中,你可能需要扩展或自定义查找表。

  • 灵活性:由于Lookup Lemmatizer不考虑词性和上下文,它在某些复杂语境下的表现可能不如基于规则或其他更高级的方法准确。

通过这种方式,Lookup Lemmatizer提供了一种简便的方式来实现词形还原,尤其适合那些对词形还原要求不高或希望简化处理流程的应用场景。

2. Rule-based Lemmatizer(基于规则的词形还原器)

基于规则的词形还原器是一种更为复杂的词形还原方法,它依赖于词性标注(POS tagging)和形态信息来确定单词的基本形式(lemma)。这种方法比查找表(lookup)方法更灵活,但也需要更多的数据和配置。以下是详细的解释:

工作原理

  1. 依赖词性和形态信息

    • 词性标注器或形态分析器:基于规则的词形还原器需要一个词性标注器(tagger)或形态分析器(morphologizer),这些组件可以为每个单词分配粗粒度的词性标签(coarse-grained POS tags)和形态特征(morphological features)。
    • 规则表:这些规则表通常来自spacy-lookups-data包,定义了如何根据词性和形态特征将单词的表面形式映射到其基本形式。
  2. 规则映射

    • 确定性映射:基于规则的词形还原器通过查阅规则表,将单词的表面形式映射为其基本形式。这个过程基于之前分配的词性和形态信息,而不是上下文。
    • 例外列表:除了规则表外,基于规则的词形还原器还接受基于列表的例外文件。对于英语,这些例外文件通常来自WordNet等资源。这些例外文件包含了那些不符合常规规则的特殊词汇及其对应的词元。

使用场景

  • 训练管道:当你在训练包含词性标注器或形态分析器的处理管道时,可以添加基于规则的词形还原器。这使得词形还原更加准确,特别是在处理复杂语法规则的语言时。

  • 数据准备:你需要从spacy-lookups-data包中获取规则表,并确保你的处理管道已经包含了词性标注器或形态分析器。

示例流程

  1. 安装spacy-lookups-data

    pip install spacy-lookups-data
    
  2. 创建并配置SpaCy处理管道
    以下是一个示例代码,展示如何在包含词性标注器的处理管道中添加基于规则的词形还原器:

    import spacy
    from spacy.lang.en import English
    from spacy.lookups import Lookups
    
    # 创建一个空的英语nlp对象
    nlp = English()
    
    # 添加词性标注器
    tagger = nlp.add_pipe("tagger")
    
    # 加载查找表数据
    lookups = Lookups()
    lookups.from_disk("/path/to/lookups-data")  # 替换为实际路径
    
    # 添加基于规则的词形还原器
    lemmatizer = nlp.add_pipe("lemmatizer", config={"mode": "rule"})
    lemmatizer.lookups = lookups
    
    # 测试
    doc = nlp("running runs ran")
    for token in doc:
        print(token.text, token.pos_, token.lemma_)
    

四、句法依赖解析器(syntactic dependency parser)

SpaCy 提供了一个快速且准确的句法依赖解析器(syntactic dependency parser),它可以帮助你分析句子中单词之间的语法关系。依赖解析是自然语言处理(NLP)中的一个重要任务,它可以揭示句子结构并帮助理解词语之间的依存关系。以下是详细的解释:

主要功能

  1. 依赖解析器

    • 句法依赖树:依赖解析器会生成一个句法依赖树,其中每个词都被分配一个依存关系标签(dependency label),表示该词与句子中其他词的关系。例如,主语(nsubj)、宾语(dobj)、修饰语(amod)等。
    • 丰富的API:SpaCy 提供了丰富的API来导航和操作这个依赖树。你可以轻松地遍历树中的节点、查找特定类型的依存关系等。
  2. 句子边界检测

    • 句子分割:依赖解析器还支持句子边界检测(sentence boundary detection),即自动识别文本中的句子边界。这对于将长文本分割成独立的句子非常有用。
  3. 基础名词短语(Base Noun Phrases)

    • “Chunks”:依赖解析器还可以用于提取基础名词短语(通常称为“chunks”)。这些名词短语通常是名词及其修饰成分组成的短语,如“the big dog”或“John’s house”。

检查是否已进行依赖解析

为了确保你的 Doc 对象已经进行了依赖解析,可以使用以下方法:

  • doc.has_annotation("DEP"):这是一个布尔值函数,检查 Token.dep 属性是否已被设置。如果返回 True,说明文档已经经过依赖解析;如果返回 False,则表示文档尚未进行依赖解析。
if doc.has_annotation("DEP"):
    print("文档已进行依赖解析")
else:
    print("文档未进行依赖解析")
  • 异常处理:如果文档没有进行依赖解析,并且你尝试使用默认的句子迭代器或其他依赖于解析结果的功能,可能会引发异常。因此,在实际应用中,建议在使用这些功能之前先检查文档是否已经进行了依赖解析。

示例代码

以下是一个示例代码,展示了如何使用 SpaCy 进行依赖解析,并检查文档是否已经进行了依赖解析:

import spacy

# 加载英语模型
nlp = spacy.load("en_core_web_sm")

# 处理一段文本
text = "The quick brown fox jumps over the lazy dog."
doc = nlp(text)

# 检查文档是否已经进行了依赖解析
if doc.has_annotation("DEP"):
    print("文档已进行依赖解析")
    
    # 遍历句子
    for sent in doc.sents:
        print(f"句子: {sent.text}")
        
        # 遍历句子中的每个词及其依存关系
        for token in sent:
            print(f"{token.text} --({token.dep_})--> {token.head.text}")
else:
    print("文档未进行依赖解析")
    # 如果未进行依赖解析,可以在此处添加相应的处理逻辑

注意事项

  • 模型要求:依赖解析需要一个预训练的模型,如 en_core_web_sm。确保你在处理文本之前加载了适当的模型。

  • 性能优化:对于大规模文本处理,依赖解析可能会消耗较多资源。根据具体需求,可以选择更轻量级的模型或调整处理流程以提高效率。

通过这种方式,SpaCy 的依赖解析功能可以帮助你深入理解句子结构,提取重要的语法信息,并支持各种高级的自然语言处理任务。

Dependency label scheme
有关 spaCy 模型分配的句法依赖关系标签的列表 不同的语言,请参阅 模型目录

1. 名词短语(Noun Chunks)

名词短语(noun chunks),也称为“基础名词短语”(base noun phrases),是指那些以名词为核心,并包含描述该名词的其他词语的平坦短语。名词短语在自然语言处理中非常重要,因为它们通常代表了句子中的主要概念或实体。

名词短语的构成

  1. 核心名词:名词短语的核心是一个名词(head noun),它可以是单数或复数形式。
  2. 修饰成分:围绕核心名词的其他词语通常是形容词、限定词(如冠词)、介词短语或其他修饰词,这些词语共同描述或限定核心名词。

例如:

  • “the lavish green grass” 中,“grass” 是核心名词,而 “the lavish green” 是修饰成分。
  • “the world’s largest tech fund” 中,“fund” 是核心名词,而 “the world’s largest tech” 是修饰成分。

如何获取名词短语

在 SpaCy 中,获取文档中的名词短语非常简单,只需遍历 Doc.noun_chunks 属性即可。每个名词短语都是一个 Span 对象,表示一个连续的词语序列。

以下是具体的示例代码:

import spacy

# 加载英语模型
nlp = spacy.load("en_core_web_sm")

# 处理一段文本
text = "The quick brown fox jumps over the lavish green grass and the world's largest tech fund."
doc = nlp(text)

# 遍历并打印文档中的名词短语
for chunk in doc.noun_chunks:
    print(chunk.text)

示例输出

假设你运行上述代码,输出可能如下:

The quick brown fox
the lavish green grass
the world's largest tech fund

详细说明

  1. Doc.noun_chunks

    • 这是一个生成器,返回文档中的所有名词短语(Span 对象)。
    • 每个 Span 对象包含了从文档中提取的名词短语及其相关信息。
  2. 名词短语的特点

    • 平坦结构:名词短语是平坦的(flat),意味着它们不嵌套其他复杂的语法结构。
    • 直接访问:通过 Doc.noun_chunks 可以直接访问和操作名词短语,无需复杂的解析逻辑。
  3. 应用场景

    • 信息提取:名词短语通常包含重要的信息,如实体名称、主题等,因此在信息提取任务中非常有用。
    • 摘要生成:在自动摘要生成中,名词短语可以帮助识别关键概念和重要细节。
    • 搜索引擎优化:在搜索引擎优化(SEO)中,名词短语可以用来识别用户搜索的关键术语和短语。

扩展功能

除了简单的遍历,你还可以进一步分析名词短语的内部结构。例如,你可以检查每个名词短语的核心名词及其修饰成分:

for chunk in doc.noun_chunks:
    print(f"名词短语: {chunk.text}")
    print(f"核心名词: {chunk.root.text}")
    print(f"修饰成分: {' '.join([token.text for token in chunk if token != chunk.root])}")
    print()

这将输出类似以下内容:

名词短语: The quick brown fox
核心名词: fox
修饰成分: The quick brown

名词短语: the lavish green grass
核心名词: grass
修饰成分: the lavish green

名词短语: the world's largest tech fund
核心名词: fund
修饰成分: the world's largest tech

通过这种方式,你可以更深入地理解名词短语的组成结构,并根据需要进行进一步的处理和分析。名词短语在自然语言处理中有广泛的应用,掌握如何提取和分析它们对于许多任务都至关重要。

2. 句法依存树(Navigating the Parse Tree)

在自然语言处理中,依存解析(dependency parsing)是揭示句子结构的重要工具。SpaCy 提供了一个强大的依存解析器,能够生成句法依存树,并提供了丰富的API来导航和操作这些树。以下是关于如何在 SpaCy 中导航依存树的详细解释。

关键术语

  1. Head(核心词)

    • 在依存树中,每个词语都有一个直接的核心词(head),表示该词语与哪个词语存在直接的依存关系。
  2. Child(子节点)

    • 子节点是指那些依赖于某个核心词的词语。在一个依存关系中,子节点通过一条弧连接到其核心词。
  3. Dep(依存标签)

    • 依存标签(dep)描述了子节点与核心词之间的具体语法关系类型。例如,主语(nsubj)、宾语(dobj)、修饰语(amod)等。
    • .dep 是依存标签的哈希值,而 .dep_ 是对应的字符串值。

获取依存关系信息

在 SpaCy 中,你可以通过 Token 对象访问依存关系信息。以下是一些常用的方法和属性:

  • .head:获取当前词语的核心词(head word)。
  • .children:获取当前词语的所有子节点(child words)。
  • .dep:获取当前词语与其核心词之间依存关系的哈希值。
  • .dep_:获取当前词语与其核心词之间依存关系的字符串标签。

示例代码

以下是一个示例代码,展示了如何使用 SpaCy 来导航和分析依存树中的关系:

import spacy

# 加载英语模型
nlp = spacy.load("en_core_web_sm")

# 处理一段文本
text = "The quick brown fox jumps over the lazy dog."
doc = nlp(text)

# 遍历文档中的每个词语
for token in doc:
    print(f"词语: {token.text}")
    print(f"核心词: {token.head.text}")
    print(f"依存关系标签: {token.dep_}")
    print(f"子节点: {[child.text for child in token.children]}")
    print()

示例输出

假设你运行上述代码,输出可能如下:

词语: The
核心词: fox
依存关系标签: det
子节点: []

词语: quick
核心词: fox
依存关系标签: amod
子节点: []

词语: brown
核心词: fox
依存关系标签: amod
子节点: []

词语: fox
核心词: jumps
依存关系标签: nsubj
子节点: [The, quick, brown]

词语: jumps
核心词: ROOT
依存关系标签: ROOT
子节点: [fox, over]

词语: over
核心词: jumps
依存关系标签: prep
子节点: [dog]

词语: the
核心词: dog
依存关系标签: det
子节点: []

词语: lazy
核心词: dog
依存关系标签: amod
子节点: []

词语: dog
核心词: over
依存关系标签: pobj
子节点: [the, lazy]

输出解释

  1. 词语及其核心词

    • 每个词语都指向它的核心词(head)。例如,“quick” 和 “brown” 的核心词都是 “fox”,因为它们修饰“fox”。
  2. 依存关系标签

    • 依存关系标签描述了词语之间的语法关系。例如,“fox”的依存关系标签是“nsubj”,表示它是动词“jumps”的主语。
  3. 子节点

    • 子节点列表列出了所有依赖于当前词语的词语。例如,“fox”的子节点包括“The”、“quick”和“brown”,因为这些词修饰“fox”。

进一步分析

除了简单的遍历,你还可以进行更复杂的分析,例如查找特定类型的依存关系或构建整个依存树的可视化图。

例如,查找所有名词短语(NP)并打印它们:

for token in doc:
    if token.pos_ == "NOUN":
        subtree = list(token.subtree)
        print(f"名词短语: {' '.join([t.text for t in subtree])}")

通过这种方式,你可以深入理解句子的结构,并根据需要进行进一步的处理和分析。依存解析在许多自然语言处理任务中都非常重要,如信息提取、问答系统和情感分析等。掌握如何导航和操作依存树将极大地增强你的文本分析能力。

a. 在局部树中迭代(Iterating Around the Local Tree)

在 SpaCy 中,除了基本的依存关系属性(如 .head.children),还有一些方便的属性可以帮助你在局部树(local tree)中进行更细致的遍历和分析。这些属性特别适用于需要关注某个词语在其上下文中的具体位置和关系的情况。

关键属性

  1. Token.leftsToken.rights

    • Token.lefts:返回当前词语左侧的所有子节点(即在句子顺序中位于当前词语之前的子节点)。
    • Token.rights:返回当前词语右侧的所有子节点(即在句子顺序中位于当前词语之后的子节点)。
    • 这两个属性返回的是按句子顺序排列的子节点序列。
  2. Token.n_leftsToken.n_rights

    • Token.n_lefts:返回当前词语左侧子节点的数量。
    • Token.n_rights:返回当前词语右侧子节点的数量。
    • 这两个属性返回的是整数值,表示子节点的数量。

示例代码

以下是一个示例代码,展示了如何使用这些属性来遍历和分析局部树:

import spacy

# 加载英语模型
nlp = spacy.load("en_core_web_sm")

# 处理一段文本
text = "The quick brown fox jumps over the lazy dog."
doc = nlp(text)

# 遍历文档中的每个词语
for token in doc:
    print(f"词语: {token.text}")
    print(f"核心词: {token.head.text}")
    print(f"依存关系标签: {token.dep_}")
    
    # 左侧子节点
    left_children = list(token.lefts)
    if left_children:
        print(f"左侧子节点: {[child.text for child in left_children]}")
    else:
        print("无左侧子节点")
    
    # 右侧子节点
    right_children = list(token.rights)
    if right_children:
        print(f"右侧子节点: {[child.text for child in right_children]}")
    else:
        print("无右侧子节点")
    
    # 左侧和右侧子节点数量
    print(f"左侧子节点数量: {token.n_lefts}")
    print(f"右侧子节点数量: {token.n_rights}")
    print()

示例输出

假设你运行上述代码,输出可能如下:

词语: The
核心词: fox
依存关系标签: det
无左侧子节点
无右侧子节点
左侧子节点数量: 0
右侧子节点数量: 0

词语: quick
核心词: fox
依存关系标签: amod
无左侧子节点
无右侧子节点
左侧子节点数量: 0
右侧子节点数量: 0

词语: brown
核心词: fox
依存关系标签: amod
无左侧子节点
无右侧子节点
左侧子节点数量: 0
右侧子节点数量: 0

词语: fox
核心词: jumps
依存关系标签: nsubj
左侧子节点: [The, quick, brown]
右侧子节点: []
左侧子节点数量: 3
右侧子节点数量: 0

词语: jumps
核心词: ROOT
依存关系标签: ROOT
左侧子节点: [fox]
右侧子节点: [over]
左侧子节点数量: 1
右侧子节点数量: 1

词语: over
核心词: jumps
依存关系标签: prep
左侧子节点: []
右侧子节点: [the, lazy, dog]
左侧子节点数量: 0
右侧子节点数量: 3

词语: the
核心词: dog
依存关系标签: det
无左侧子节点
右侧子节点: [lazy, dog]
左侧子节点数量: 0
右侧子节点数量: 2

词语: lazy
核心词: dog
依存关系标签: amod
左侧子节点: [the]
右侧子节点: [dog]
左侧子节点数量: 1
右侧子节点数量: 1

词语: dog
核心词: over
依存关系标签: pobj
左侧子节点: [the, lazy]
无右侧子节点
左侧子节点数量: 2
右侧子节点数量: 0

输出解释

  1. 左侧子节点 (Token.lefts)

    • 对于“fox”,其左侧子节点是修饰它的形容词“quick”和“brown”,以及限定词“The”。
  2. 右侧子节点 (Token.rights)

    • 对于“jumps”,其右侧子节点是介词短语“over the lazy dog”中的“over”。
    • 对于“over”,其右侧子节点是名词短语“the lazy dog”中的所有词语。
  3. 子节点数量 (Token.n_leftsToken.n_rights)

    • “fox”有3个左侧子节点(“The”、“quick”、“brown”),没有右侧子节点。
    • “over”没有左侧子节点,有3个右侧子节点(“the”、“lazy”、“dog”)。

通过这些属性,你可以更灵活地分析词语在其局部树中的位置和关系,这对于理解句子结构和提取特定信息非常有用。例如,在构建语法树、识别复杂短语或进行细粒度的句法分析时,这些属性可以提供重要的帮助。

b. 使用依存树进行分析和信息提取

Combining models and rules
有关如何编写基于规则的信息提取逻辑的更多示例 利用模型中不同组件产生的预测, 请参阅使用指南 结合模型和规则

在 SpaCy 中,依存解析不仅可以帮助你理解句子的结构,还可以用于信息提取等高级任务。通过利用一些关键属性,如 .subtree.ancestors.left_edge.right_edge,你可以更灵活地导航依存树并提取有用的信息。

关键属性及其用法

  1. Token.subtree

    • 返回以当前词语为核心词(head)的整个子树中的所有词语,按句子顺序排列。
    • 这对于获取一个完整的短语非常有用。
  2. Token.ancestors

    • 返回当前词语的所有祖先节点(即从当前词语向上追溯到根节点的所有词语)。
    • 这有助于理解词语在其上下文中的层次关系。
  3. Token.is_ancestor

    • 检查一个词语是否是另一个词语的祖先节点。
    • 例如,可以用来判断某个词语是否包含另一个词语。
  4. Token.left_edgeToken.right_edge

    • Token.left_edge:返回当前词语所在子树的第一个词语。
    • Token.right_edge:返回当前词语所在子树的最后一个词语。
    • 这些属性对于创建 Span 对象非常有用,因为它们提供了子树的边界。

示例代码:提取货币值及其对应的名词短语

以下是一个示例代码,展示了如何结合命名实体识别(NER)和依存解析来提取货币值及其对应的名词短语:

import spacy

# 加载英语模型
nlp = spacy.load("en_core_web_sm")

# 处理一段文本
text = "Net income was $9.4 million and the company reported earnings of $3.5 billion."
doc = nlp(text)

# 遍历文档中的命名实体
for ent in doc.ents:
    if ent.label_ == "MONEY":
        # 获取货币值的依存头词
        head = ent.root.head
        
        # 获取头词的完整名词短语
        noun_phrase = None
        for chunk in doc.noun_chunks:
            if head in chunk:
                noun_phrase = chunk
                break
        
        if noun_phrase:
            print(f"货币值: {ent.text}")
            print(f"对应的名词短语: {noun_phrase.text}")
        else:
            print(f"货币值: {ent.text} 未找到对应的名词短语")

示例输出

假设你运行上述代码,输出可能如下:

货币值: $9.4 million
对应的名词短语: Net income
货币值: $3.5 billion
对应的名词短语: earnings

解释

  1. 命名实体识别(NER)

    • 使用 SpaCy 的 NER 功能识别出文本中的货币值(MONEY 实体),例如 $9.4 million$3.5 billion
  2. 依存解析

    • 对于每个识别出的货币值,获取其核心词(ent.root.head),然后查找该核心词所在的完整名词短语(noun_chunk)。
    • 通过遍历 doc.noun_chunks,找到包含核心词的名词短语。
  3. 使用 Token.left_edgeToken.right_edge 创建 Span 对象

    • 如果需要创建一个 Span 对象来表示一个完整的语法短语,可以使用 .left_edge.right_edge 来确定短语的边界。
    • 例如,要创建一个 Span 对象表示“Net income”:
from spacy.tokens import Span

# 假设我们已经找到了“Net income”的范围
start_token = doc[0]  # "Net"
end_token = doc[2]    # "income"

span = Span(doc, start_token.i, end_token.i + 1)
print(span.text)  # 输出 "Net income"

注意,在使用 .right_edge 作为范围的终点时,不要忘记加1(+1),因为 Span 对象的结束索引是开区间(不包括该索引位置的词语)。

结合其他预测

依存解析可以与其他预测(如命名实体识别)结合使用,以实现更复杂的信息提取任务。例如,上述示例展示了如何结合 NER 和依存解析来提取货币值及其对应的名词短语,这对于财务报告、新闻文章等文本中的信息提取非常有用。

通过这种方式,你可以充分利用 SpaCy 提供的丰富功能,构建强大的自然语言处理应用。

3. 可视化依赖关系

理解 spaCy 依赖解析器的最佳方式是交互方式。为了简化此操作,spaCy 附带了一个可视化模块。您可以将Doc或Doc对象列表传递给 displaCy 并运行 displacy.serve运行 Web 服务器,或者 displacy.render生成原始标记。如果你想知道如何编写与某种句法结构挂钩的规则,只需将句子插入可视化工具,然后看看 spaCy 如何对其进行注释。

import spacy
from spacy import displacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("Autonomous cars shift insurance liability toward manufacturers")
# Since this is an interactive Jupyter environment, we can use displacy.render here
displacy.render(doc, style='dep')

有关更多详细信息和示例,请参阅 可视化 spaCy 的使用指南。您还可以在我们的在线演示中测试 displaCy。

4. 禁用句式依赖解析器

在 spaCy 提供的训练管道中,解析器被加载并 默认启用 标准处理管道。如果您不需要任何语法信息,则应禁用解析器。禁用解析器将使 spaCy 加载和运行速度更快。如果您想加载解析器,但需要针对特定​​文档禁用它,您还可以控制它在nlp对象上的使用。有关更多详细信息,请参阅使用指南 禁用管道组件

nlp = spacy.load("en_core_web_sm", disable=["parser"])

五、命名实体识别(Named Entity Recognition, NER)

命名实体识别(NER)是自然语言处理(NLP)中的一个重要任务,旨在从文本中识别并分类出具有特定意义的实体。SpaCy 提供了一个快速且高效的统计实体识别系统,能够为连续的词语序列(spans of tokens)分配标签。以下是关于 SpaCy 中 NER 的详细解释及其功能特点。

主要功能

  1. 快速统计实体识别系统

    • SpaCy 使用统计模型来识别和分类文本中的命名实体。该系统非常高效,能够在大规模文本数据上进行实时处理。
  2. 默认支持的实体类型

    • SpaCy 的预训练模型可以识别多种命名实体和数值实体,包括但不限于以下类别:
      • PERSON:人名
      • ORG:组织、公司
      • GPE:国家、城市、州等地理政治实体
      • LOC:非政治地理位置(如山脉、河流)
      • DATE:日期
      • TIME:时间
      • MONEY:货币金额
      • PRODUCT:产品名称
      • EVENT:事件(如战争、节日)
      • WORK_OF_ART:艺术作品(如书籍、电影)
      • LAW:法律条文或法规
      • LANGUAGE:语言名称
  3. 自定义实体类别

    • 除了默认支持的实体类别外,用户还可以根据需要添加任意类别的实体,并更新模型以包含新的示例。这使得 SpaCy 的 NER 系统非常灵活,适用于各种应用场景。

如何使用 SpaCy 进行 NER

以下是一个简单的示例代码,展示了如何使用 SpaCy 进行命名实体识别:

import spacy

# 加载英语模型
nlp = spacy.load("en_core_web_sm")

# 处理一段文本
text = "Apple is looking at buying U.K.-based startup for $1 billion."
doc = nlp(text)

# 遍历文档中的命名实体
for ent in doc.ents:
    print(ent.text, ent.label_)

示例输出

假设你运行上述代码,输出可能如下:

Apple ORG
U.K. GPE
$1 billion MONEY

解释

  1. doc.ents

    • doc.ents 是一个生成器,返回文档中所有识别出的命名实体(Span 对象)。每个实体都有一个 .label_ 属性,表示其类别标签。
  2. 自定义实体类别

    • 如果你需要识别新的实体类别,可以通过以下步骤实现:
      1. 创建一个新的 EntityRuler
        from spacy.pipeline import EntityRuler
        ruler = EntityRuler(nlp)
        
      2. 定义模式并添加到 EntityRuler
        patterns = [{"label": "ANIMAL", "pattern": "cat"}, {"label": "ANIMAL", "pattern": "dog"}]
        ruler.add_patterns(patterns)
        
      3. EntityRuler 添加到管道
        nlp.add_pipe(ruler, before="ner")
        
  3. 更新模型

    • 如果你想通过提供新的示例来更新现有的 NER 模型,可以使用 SpaCy 的 spacy.training.Examplenlp.update() 方法。例如:
      import random
      from spacy.training import Example
      
      # 准备训练数据
      TRAIN_DATA = [
          ("Google was founded by Larry Page and Sergey Brin.", {"entities": [(0, 6, "ORG"), (22, 33, "PERSON"), (37, 49, "PERSON")]}),
          ("Microsoft is headquartered in Redmond, Washington.", {"entities": [(0, 9, "ORG"), (30, 37, "GPE"), (40, 50, "GPE")]})
      ]
      
      # 更新模型
      optimizer = nlp.resume_training()
      for i in range(10):
          random.shuffle(TRAIN_DATA)
          for text, annotations in TRAIN_DATA:
              doc = nlp.make_doc(text)
              example = Example.from_dict(doc, annotations)
              nlp.update([example], sgd=optimizer)
      

结合其他功能

NER 可以与其他 SpaCy 功能结合使用,以实现更复杂的信息提取任务。例如:

  • 依存解析:结合依存解析可以帮助你理解实体之间的关系。例如,提取某个组织的总部地点。

    for ent in doc.ents:
        if ent.label_ == "ORG":
            head = ent.root.head
            if head.dep_ == "prep" and head.right_edge.ent_type_ == "GPE":
                location = head.right_edge
                print(f"{ent.text} 总部位于 {location.text}")
    
  • 名词短语提取:结合名词短语提取可以帮助你找到与实体相关的更多信息。例如,提取某个产品的描述。

    for ent in doc.ents:
        if ent.label_ == "PRODUCT":
            noun_chunks = [chunk for chunk in doc.noun_chunks if ent.root in chunk]
            if noun_chunks:
                print(f"{ent.text} 描述: {noun_chunks[0].text}")
    

通过这些方法,你可以充分利用 SpaCy 的 NER 功能,构建强大的信息提取和分析工具。无论是用于商业智能、新闻摘要还是学术研究,NER 都是理解和处理自然语言的重要手段。

使用 spaCy 的内置displaCy 可视化工具,示例,命名实体如下所示:

在这里插入图片描述

1. 访问实体标签

下面描述如何使用spaCy库进行实体抽取,并解释访问这些实体注解和标签的标准方法。下面是详细的解释:

  1. 访问实体注解和标签

    • 在spaCy中,通过doc.ents属性可以访问文档中的命名实体(Named Entities),它返回一个Span对象的序列。每个Span对象代表文档中的一个实体。
    • 实体类型可以通过两种方式获取:一种是作为哈希值(使用ent.label),另一种是作为字符串(使用ent.label_)。
    • Span对象可以被当作一个Token序列来处理,这意味着你可以遍历这个实体或者对其进行索引操作。此外,你还可以将整个实体转换为文本形式,就像它是一个单独的Token一样。
  2. 通过Token访问实体注解

    • 除了直接访问实体外,你还可以通过单个Token的注解来了解实体信息。具体来说,token.ent_iobtoken.ent_type这两个属性提供了这种功能。
    • token.ent_iob属性指示了一个Token是否是某个实体的开始、中间或结束部分。如果该Token不属于任何实体,则返回空字符串。
    • token.ent_type属性则显示了与Token关联的实体类型,如果没有设置实体类型,则同样返回空字符串。

这种机制使得开发者能够有效地从文本中提取并处理信息,例如识别出人名、地名、组织机构等特定类型的实体,从而支持更复杂的自然语言处理任务。

import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("San Francisco considers banning sidewalk delivery robots")

# document level
ents = [(e.text, e.start_char, e.end_char, e.label_) for e in doc.ents]
print(ents)

# token level
ent_san = [doc[0].text, doc[0].ent_iob_, doc[0].ent_type_]
ent_francisco = [doc[1].text, doc[1].ent_iob_, doc[1].ent_type_]
print(ent_san)  # ['San', 'B', 'GPE']
print(ent_francisco)  # ['Francisco', 'I', 'GPE']

在这里插入图片描述

2. 设置实体标签

在使用spaCy进行命名实体识别(NER)时,如何设置或更新文档中的实体注解。以下是详细的解析:

  1. 一致性要求

    • 为了确保Token注解序列的一致性,在设置实体注解时需要在文档级别进行操作。这意味着你不能直接修改单个Token的token.ent_iobtoken.ent_type属性。
  2. 设置方法

    • 最简单的设置实体的方法是通过doc.set_ents()函数,并创建一个新的Span对象来表示这个实体。
    • doc.set_ents()允许你将一个或多个新的Span对象添加到doc.ents中,从而更新文档中的实体信息。
  3. Span对象初始化

    • Span对象通常通过指定开始和结束的Token索引来初始化,而不是字符偏移量。例如,如果你知道某个实体从第5个Token开始,到第8个Token结束,你可以用这些索引创建一个Span对象。
  4. 从字符偏移量创建Span

    • 如果你需要根据字符位置(而非Token索引)来定义实体,可以使用Doc.char_span()方法。这个方法接受字符起始和结束偏移量作为参数,然后返回一个基于这些字符偏移量的Span对象。
    • 这对于那些需要根据文本中的具体字符位置来确定实体边界的场景特别有用。

示例应用

假设你有一个句子:“Apple is looking at buying U.K.-based startup for $1 billion”,你想标记“Apple”为ORG,“U.K.”为GPE,“$1 billion”为MONEY。你可以先找到对应的Token索引,然后使用doc.set_ents()结合新创建的Span对象来完成这项工作。如果需要根据字符位置来创建这些Span对象,则可以使用Doc.char_span()方法。

这种方法提供了灵活性和控制力,使得开发者可以根据实际需求精确地设置和管理文本中的实体信息。

import spacy
from spacy.tokens import Span

nlp = spacy.load("en_core_web_sm")
doc = nlp("fb is hiring a new vice president of global policy")
ents = [(e.text, e.start_char, e.end_char, e.label_) for e in doc.ents]
print('Before', ents)
# The model didn't recognize "fb" as an entity :(

# Create a span for the new entity
fb_ent = Span(doc, 0, 1, label="ORG")
orig_ents = list(doc.ents)

# Option 1: Modify the provided entity spans, leaving the rest unmodified
doc.set_ents([fb_ent], default="unmodified")

# Option 2: Assign a complete list of ents to doc.ents
doc.ents = orig_ents + [fb_ent]

ents = [(e.text, e.start, e.end, e.label_) for e in doc.ents]
print('After', ents)
# [('fb', 0, 1, 'ORG')] 🎉

使用 Doc.char_span

fb_ent = doc.char_span(0, 2, label="ORG")

3. 使用doc.from_array设置实体标签

在spaCy中,doc.from_array方法提供了一种从数组数据结构导入Token属性的方式,包括设置实体注解(entity annotations)。这种方法对于那些希望从外部数据源或自定义处理流程中导入信息到spaCy文档中的用户非常有用。以下是关于如何使用doc.from_array来设置实体注解的详细解释:

  1. 准备数组

    • 首先,你需要准备一个二维数组(通常是NumPy数组),其中每一行对应于文档中的一个Token,并且每一列代表不同的属性。
    • 对于设置实体注解而言,至少需要包含两个特定的属性:ENT_TYPEENT_IOBENT_TYPE指定了实体类型(如PERSON, ORG, GPE等),而ENT_IOB则指示了该Token是实体的开始(B-)、中间部分(I-)还是不属于任何实体(O)。
  2. 导入属性

    • 使用doc.from_array方法时,你需要将上述准备好的数组作为输入传递给它。此外,还需要指定一个属性名称列表,以告诉spaCy数组中的每列对应哪个Token属性。
    • 例如,如果你的数组包含ENT_TYPEENT_IOB两列,则相应的属性名称列表应为["ENT_TYPE", "ENT_IOB"]
  3. 更新文档

    • doc.from_array会根据提供的数组更新文档中的每个Token的相应属性。这意味着,通过正确配置你的数组,你可以直接设置文档中所有Token的实体注解,从而避免手动逐个修改每个Token的繁琐过程。

示例

假设你有一个简单的句子:“Berlin is a nice city.”,并且你想要标记“Berlin”为GPE实体。你可以创建如下所示的数组并使用doc.from_array进行设置:

import spacy
import numpy as np

nlp = spacy.blank("en")
doc = nlp("Berlin is a nice city.")

# 准备数组,第一列表示ENT_TYPE,第二列表示ENT_IOB
arr = np.array([['GPE', 'B'], ['', 'O'], ['', 'O'], ['', 'O']])

# 设置属性名称列表
attr_names = ["ENT_TYPE", "ENT_IOB"]

# 使用from_array方法更新doc对象
doc.from_array(attr_names, arr)

# 打印结果
for ent in doc.ents:
    print(ent.text, ent.label_)

这段代码将会输出:

Berlin GPE

这种方法特别适用于需要批量处理大量文本或从其他格式的数据转换到spaCy格式的情况。

4. 使用Cython设置实体标签

在spaCy中设置实体注解的另一种高级方法是通过Cython直接操作底层数据结构。这种方法适合那些需要高性能和对细节有严格控制的应用场景。以下是对此方法的详细解释:

  1. Cython简介

    • Cython是一种编程语言,它是Python的一个超集,允许你编写C扩展以提高性能。它非常适合用于需要高效处理大量数据的任务。
  2. 直接访问底层结构

    • 在spaCy内部,文档、词符(Token)等对象都是用C语言实现的,并且这些对象的数据存储在内存中的结构体(如TokenC*结构体)里。
    • 通过编写Cython函数,你可以直接访问并修改这些结构体,从而绕过Python层面的一些限制,达到更高的执行效率。
  3. 注意事项

    • 直接操作这些底层结构意味着你需要确保数据的一致性和正确性。例如,如果你手动设置了某个Token的ENT_TYPEENT_IOB标签,你需要确保这些更改不会破坏其他依赖于这些属性的功能或算法。
    • 这种方式要求开发者对spaCy的内部实现有一定的了解,包括如何正确地读取和写入数据结构,以及如何避免潜在的并发问题或其他不一致状态。
  4. 示例流程

    • 编写一个Cython函数,该函数接收一个Doc对象和你想要设置的实体信息。
    • 在函数内部,获取指向Doc对象底层TokenC*结构体数组的指针。
    • 根据你的需求,直接修改特定TokenC*结构体中的ENT_TYPEENT_IOB字段。
    • 确保所有修改后的数据保持一致,特别是当你涉及到跨多个Token的实体时。

示例代码框架

虽然具体的实现会根据实际需求有所不同,但这里提供一个简化的伪代码框架来说明这个过程:

from cymem.cymem cimport Pool
from spacy.structs cimport TokenC

cdef set_entity_annotations(Doc doc, list entity_data):
    # 假设entity_data是一个包含(start, end, label)元组的列表
    cdef Pool mem = doc.mem
    cdef TokenC* tokens = <TokenC*>doc.c
    for start, end, label in entity_data:
        for i in range(start, end):
            # 设置ENT_IOB和ENT_TYPE
            tokens[i].ent_iob = 3  # B-表示开始
            tokens[i].ent_type = hash_string(label)

注意:上述代码只是一个示意性的框架,实际应用中需要考虑更多细节,如错误处理、边界检查等。

总结

直接使用Cython操作spaCy的底层结构可以显著提高性能,但同时也增加了复杂性和出错的可能性。因此,这种方法更适合有经验的开发者,他们需要在性能优化和复杂度之间做出权衡,并且愿意承担维护这种代码的责任。对于大多数用户来说,使用更高层次的API(如doc.set_ents()doc.from_array)已经足够满足需求。

Annotation scheme
有关 spaCy 训练管道中可用的实体类型的详细信息,请参阅 各个模型的“标签方案”部分 模型目录

5. 使用 displaCy 可视化命名实体

import spacy
from spacy import displacy

text = "When Sebastian Thrun started working on self-driving cars at Google in 2007, few people outside of the company took him seriously."

nlp = spacy.load("en_core_web_sm")
doc = nlp(text)
displacy.serve(doc, style="ent")

在这里插入图片描述
有关更多详细信息和示例,请参阅 可视化 spaCy 的使用指南

displaCy 是 spaCy 提供的一个可视化工具,专门用于展示命名实体识别(Named Entity Recognition, NER)模型的输出结果。它使得用户能够以一种直观且交互的方式探索和理解NER模型的行为。以下是关于如何使用 displaCy 进行命名实体可视化的详细解释:

  1. displaCy ENT 可视化器

    • displaCy ENT 是 displaCy 工具的一部分,专注于显示文本中的命名实体。
    • 它允许你查看哪些词或短语被标记为特定类型的实体(如人名、地点、组织等),以及这些实体在文档中的位置。
  2. 可视化方法

    • 通过服务器展示:如果你想要一个可以交互的网页界面来查看你的NER结果,你可以使用 displacy.serve 函数。这个函数启动一个本地Web服务器,并在浏览器中打开一个页面来展示你的数据。
      import spacy
      from spacy import displacy
      
      nlp = spacy.load("en_core_web_sm")
      doc = nlp("Apple is looking at buying U.K.-based startup for $1 billion")
      
      # 启动本地服务器并展示结果
      displacy.serve([doc], style="ent")
      
    • 生成原始标记:如果你只是想生成HTML代码而不启动服务器,可以使用 displacy.render 函数。这会返回一段HTML代码,你可以将其嵌入到自己的网页或其他需要的地方。
      html = displacy.render(doc, style="ent")
      print(html)
      
  3. 输入格式

    • displacy.servedisplacy.render 都可以接受一个 Doc 对象或一个 Doc 对象列表作为输入。
    • 如果你有多个文档想要一次性处理和展示,只需将它们作为一个列表传递给上述函数即可。
  4. 自定义样式

    • 你可以通过设置一些选项来自定义 displaCy 的输出样式,比如改变颜色方案、字体大小等。例如,你可以指定一个颜色映射来为不同类型的实体应用不同的颜色。
      options = {"ents": ["PERSON", "ORG"], "colors": {"PERSON": "red", "ORG": "green"}}
      displacy.render(doc, style="ent", options=options)
      
  5. 应用场景

    • 在训练和调试NER模型时,displaCy 提供了一个非常有用的手段来快速检查模型的表现。
    • 对于教育和演示目的,它也是一个很好的工具,可以帮助学生或团队成员更好地理解NER的工作原理及其应用效果。

示例

假设你有一个简单的句子:“Apple is looking at buying U.K.-based startup for $1 billion”,并且你想要可视化其中的命名实体,你可以这样做:

import spacy
from spacy import displacy

# 加载预训练的模型
nlp = spacy.load("en_core_web_sm")
doc = nlp("Apple is looking at buying U.K.-based startup for $1 billion")

# 生成HTML代码
html = displacy.render(doc, style="ent")
print(html)

# 或者启动本地服务器进行展示
displacy.serve([doc], style="ent")

这样,你就可以看到每个被识别出的实体类型(如“Apple”被标记为ORG,“U.K.”被标记为GPE等),并且可以通过不同的颜色和格式清晰地区分它们。这对于分析和展示NER结果非常有用。

六、实体链接(Entity Linking)

实体链接是将命名实体与“现实世界”中的具体实体关联起来的过程,通常通过将文本中的实体解析为知识库(Knowledge Base, KB)中的唯一标识符来实现。spaCy 提供了执行实体链接的功能,允许用户创建自定义的知识库,并训练新的实体链接模型。

知识库和实体链接模型的创建

  1. 创建知识库

    • 为了进行实体链接,首先需要定义一个知识库(KB)。这个知识库可以包含各种实体及其相关信息。
    • spaCy 提供了创建和管理知识库的工具,你可以根据自己的需求构建一个定制化的知识库。
  2. 训练实体链接模型

    • 在拥有知识库之后,你需要训练一个实体链接模型,以便能够自动将文档中的实体映射到知识库中的对应实体。
    • spaCy 提供了相关的API和教程来帮助你完成这一过程。例如,可以通过 spaCy 的项目模板来查看如何定义知识库并训练实体链接模型的具体步骤。

示例教程链接

import spacy

# "my_custom_el_pipeline" is assumed to be a custom NLP pipeline that was trained and serialized to disk
nlp = spacy.load("my_custom_el_pipeline")
doc = nlp("Ada Lovelace was born in London")

# Document level
ents = [(e.text, e.label_, e.kb_id_) for e in doc.ents]
print(ents)  # [('Ada Lovelace', 'PERSON', 'Q7259'), ('London', 'GPE', 'Q84')]

# Token level
ent_ada_0 = [doc[0].text, doc[0].ent_type_, doc[0].ent_kb_id_]
ent_ada_1 = [doc[1].text, doc[1].ent_type_, doc[1].ent_kb_id_]
ent_london_5 = [doc[5].text, doc[5].ent_type_, doc[5].ent_kb_id_]
print(ent_ada_0)  # ['Ada', 'PERSON', 'Q7259']
print(ent_ada_1)  # ['Lovelace', 'PERSON', 'Q7259']
print(ent_london_5)  # ['London', 'GPE', 'Q84']

访问实体标识符

一旦你的模型训练完成并应用到文档中,你可以通过以下方式访问实体的唯一标识符:

  1. 通过 Span 对象访问

    • 当你有一个 Span 对象时,可以通过其 kb_idkb_id_ 属性来获取实体在知识库中的标识符。
    • kb_id 返回的是哈希值,而 kb_id_ 返回的是字符串形式的标识符。
    import spacy
    
    nlp = spacy.load("your_entity_linker_model")
    doc = nlp("Apple is a technology company based in Cupertino.")
    
    for ent in doc.ents:
        print(f"Entity: {ent.text}, KB ID: {ent.kb_id_}")
    
  2. 通过 Token 对象访问

    • 类似地,对于单个 Token 对象,也可以通过 ent_kb_ident_kb_id_ 属性来获取其对应的实体标识符。
    for token in doc:
        if token.ent_type_:
            print(f"Token: {token.text}, KB ID: {token.ent_kb_id_}")
    

示例代码

下面是一个完整的示例,展示了如何加载一个已经训练好的实体链接模型,并访问其中的实体标识符:

import spacy

# 加载已训练的实体链接模型
nlp = spacy.load("your_entity_linker_model")

# 处理文本
doc = nlp("Apple is looking at buying U.K.-based startup for $1 billion.")

# 遍历所有识别出的实体,并打印它们的文本和知识库ID
for ent in doc.ents:
    print(f"Entity: {ent.text}, KB ID: {ent.kb_id_}")

# 如果需要针对单个Token检查实体链接信息
for token in doc:
    if token.ent_type_:
        print(f"Token: {token.text}, KB ID: {token.ent_kb_id_}")

总结

  • 实体链接 是将文本中的命名实体与现实世界中的具体实体(如知识库中的条目)进行关联的过程。
  • 使用 spaCy 创建自定义知识库并训练实体链接模型后,可以通过 SpanToken 对象的特定属性(如 kb_id_ent_kb_id_)来访问实体的唯一标识符。
  • 这种方法使得从非结构化文本中提取的信息可以更准确地与结构化数据源进行对接,从而支持更复杂的自然语言处理任务。

7、未完待续

鉴于文章太长难以阅读,下面的内容放到下篇文章《SpaCy官方中文教程:一文详解SpaCy的所有功能(补充)》,敬请关注

1. Tokenization

2. Merging & Splitting of Token

3. Sentence Segmentation

4. Mappings & Exceptions

5. Word vectors and semantic similarity

6. Language Data

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值