8.2 基于规则的NER
基于规则的命名实体识别(Rule-Based Named Entity Recognition,Rule-Based NER)是一种使用预定义规则和模式匹配的方法,来识别文本中的命名实体。
8.2.1 基于规则的NER概述
与基于机器学习的方法不同,基于规则的NER不需要大量的标注数据进行训练,而是依赖于手动设计的规则集来识别实体。实现基于规则的NER的一般步骤如下所示。
- 规则设计:制定一系列规则,这些规则可以是基于词性、上下文关系、词典匹配等。规则可以包括诸如"如果一个词以大写字母开头,那么它可能是一个人名"这样的规则。
- 模式匹配:使用规则集对文本进行模式匹配。这可能包括查找特定的词性标记、识别常见的命名实体模式等。
- 实体识别:根据规则的匹配结果,确定文本中的命名实体,并将其分类到相应的类别,如人名、地名、组织名等。
- 后处理:可以进行一些后处理步骤,以提高识别的准确性。例如,可以使用上下文信息来纠正可能的错误。
基于规则的NER的优势在于它不需要大量标注好的训练数据,因此在某些特定领域或任务上可能更容易实现。然而,它也有一些限制,例如在处理复杂的语言结构和变化多样的文本时可能效果不如基于机器学习的方法。
注意:选择使用基于规则的NER还是基于机器学习的NER取决于任务的要求、可用的数据和对准确性的需求。在某些情况下,两者也可以结合使用,形成混合方法,以充分发挥各自的优势。
例如下面是一个使用基于规则的NER的例子,通过正则表达式来识别人名和日期。
实例8-1:识别人名和日期(源码路径:daima\8\name.py)
实例文件name.py的具体实现代码如下所示。
import re
def rule_based_ner(text):
# 规则1: 识别人名(假设人名由两个以及两个以上的大写字母组成)
person_names = re.findall(r'\b[A-Z][a-z]*\s[A-Z][a-z]*\b', text)
# 规则2: 识别日期(假设日期为"年-月-日"格式)
dates = re.findall(r'\b\d{4}-\d{2}-\d{2}\b', text)
return person_names, dates
# 示例文本
sample_text = "John Smith and Mary Johnson went to the party on 2023-01-15."
# 使用基于规则的NER进行实体识别
names, date_entities = rule_based_ner(sample_text)
# 输出识别的人名和日期
print("Person Names:", names)
print("Dates:", date_entities)
在上述代码中,使用两个简单的规则,一个用于识别人名,另一个用于识别日期。实际情况下,你可能需要根据任务需求和文本特点设计更复杂的规则。执行后会输出:
Person Names: ['John Smith', 'Mary Johnson']
Dates: ['2023-01-15']
8.2.2 使用SpaCy实现基于规则的NER实战
Spacy(也写作spaCy)是一个用于自然语言处理(NLP)任务的开源库和工具。它由Explosion AI公司开发,是一个用Python编写的高效、快速、开源的自然语言处理库。Spacy的设计目标是提供简单而实用的API,以及在性能上优于许多其他NLP库的实现。Spacy 提供了许多 NLP 任务的功能,主要包括:
- 分词(Tokenization):将文本分割成单独的词语或标记。
- 词性标注(Part-of-Speech Tagging):为每个词语添加词性标签,指明其在句子中的语法角色,如名词、动词等。
- 命名实体识别(Named Entity Recognition,NER):识别文本中的命名实体,如人名、地名、组织机构等。
- 依存句法分析(Dependency Parsing):分析句子中单词之间的依存关系。
- 词向量表示(Word Embeddings):提供预训练的词向量,支持词语的向量化表示。
- 文本分类(Text Classification):对文本进行分类,如情感分析、主题分类等。
- 相似度计算(Similarity):计算文本、词语或句子之间的相似度。
- 自定义规则和流水线(Custom Rules and Pipelines):允许用户根据自己的需求定义和应用自定义规则和流水线。
由于Spacy在性能上的优越性和简便的API设计,它在自然语言处理研究、开发和应用中广受欢迎。可以通过安装Spacy并加载适当的语言模型来开始使用。例如,可以使用以下命令安装Spacy:
pip install spacy
在下面的内容中,将通过一个具体实例展示使用Spacy实现基于规则的NER的过程。主要实现了如下所示的功能:
- 加载语言模型:使用 spacy.load 函数加载了英语语言模型 "en_core_web_sm",该模型包含了用于分析文本的预训练的自然语言处理工具。
- 文本处理:利用加载的语言模型处理了多个文本示例,创建了文档对象,该对象包含了经过分析和标注的文本信息。
- 词性标注和依存关系分析:对文档中的每个标记进行了遍历,提取了各标记的文本、词性标签和依存关系标签。
- 命名实体识别:使用语言模型识别了文档中的命名实体,包括人名、组织名等,并打印了它们的文本和标签。
- 实体跨度:通过文档索引获取了特定实体("iPhone X")的跨度,并打印了该实体的文本。
通过这个例子,介绍了 SpaCy 在自然语言处理中的基本用法,包括文本处理、词性标注、依存关系分析、命名实体识别等功能。这些功能使得 SpaCy 成为处理文本数据、提取信息、识别实体等自然语言处理任务的有力工具。
实例8-2:使用基于规则的NER处理多国文本(源码路径:daima\8\spacy-advanced-nlp.ipynb)
实例文件spacy-advanced-nlp.ipynb的具体实现流程如下所示。
(1)加载 SpaCy 中名为 "en_core_web_sm" 的英语语言统计模型。这个模型是一个小型的英语语言模型,它已经在各种文本来源上进行了训练,包括博客、新闻文章和评论。
nlp = spacy.load("en_core_web_sm")
一旦加载了这个模型,就可以使用 nlp 对象进行各种自然语言处理任务,例如分词、词性标注、命名实体识别等。
(2)利用 nlp 对象处理输入文本 "This is an example text"。nlp 对象对输入文本应用了一系列自然语言处理任务,并生成了一个 Doc 对象,其中包含了处理后的信息。
doc = nlp("This is a example text")
(3)使用 SpaCy 中的英语语言类,创建一个名为 nlp 的自然语言处理对象。然后,通过 nlp 对象处理了一段文本 "Progress to Contributor to make your voice count!",并将结果存储在名为 doc 的文档对象中。最后,打印了处理后的文档的文本。这个简单的示例展示了 SpaCy 的基本用法,即加载语言模型并处理文本。
# 导入英语语言类
from spacy.lang.en import English
# 创建 nlp 对象
nlp = English()
# 处理文本
doc = nlp("Progress to Contributor to make your voice count!")
# 打印文档文本
print(doc.text)
执行后会输出:
Progress to Contributor to make your voice count!
(4)使用 SpaCy 中的德语语言类,创建一个名为 nlp 的自然语言处理对象。然后,通过 nlp 对象处理了一段德语文本 "Liebe Grüße!",并将结果存储在名为 doc 的文档对象中。最后,打印了处理后的文档的文本。
# 导入德语语言类
from spacy.lang.de import German
# 创建 nlp 对象
nlp = German()
# 处理文本(这是德语的“致以亲切的问候!”)
doc = nlp("Liebe Grüße!")
# 打印文档文本
print(doc.text)
执行后会输出:
Liebe Grüße!
(5)使用 SpaCy 中的西班牙语语言类,创建一个名为 nlp 的自然语言处理对象。然后,通过 nlp 对象处理了一段西班牙语文本 "¿Cómo estás?",并将结果存储在名为 doc 的文档对象中。最后,打印了处理后的文档的文本。
# 导入西班牙语语言类
from spacy.lang.es import Spanish
# 创建 nlp 对象
nlp = Spanish()
# 处理文本(这是西班牙语的“你好吗?”)
doc = nlp("¿Cómo estás?")
# 打印文档文本
print(doc.text)
执行后会输出:
¿Cómo estás?
(6)使用 SpaCy 中的英语语言类创建了一个名为 nlp 的自然语言处理对象。然后,通过 nlp 对象处理了一段文本 "I like tree kangaroos and narwhals.",并将结果存储在名为 doc 的文档对象中。接着,通过 doc[0] 选择了文档中的第一个标记,并打印了该标记的文本。
# 导入英语语言类并创建 nlp 对象
from spacy.lang.en import English
nlp = English()
# 处理文本
doc = nlp("I like tree kangaroos and narwhals.")
# 选择第一个标记
first_token = doc[0]
# 打印第一个标记的文本
print(first_token.text)
执行后会输出:
I
(7)使用循环遍历文档中的每个标记,并打印了每个标记的文本。这样可以查看整个文本中的所有标记(单词)。
for i in doc:
print(i.text)
执行后会输出:
I
like
tree
kangaroos
and
narwhals
.
(8)首先创建了一个英语语言处理对象 nlp,然后使用该对象处理了文本 "I like tree kangaroos and narwhals.",生成了一个文档对象 doc。接下来,通过对 doc 进行切片,分别提取了 "tree kangaroos" 和 "tree kangaroos and narwhals" 这两个片段,并打印了它们的文本内容。切片操作允许我们从文档中提取特定范围的标记。
# 导入英语语言类并创建 nlp 对象
from spacy.lang.en import English
nlp = English()
# 处理文本
doc = nlp("I like tree kangaroos and narwhals.")
# 对 "tree kangaroos" 进行切片
tree_kangaroos = doc[2:4]
print(tree_kangaroos.text)
# 对 "tree kangaroos and narwhals" 进行切片(不包括句号)
tree_kangaroos_and_narwhals = doc[2:6]
print(tree_kangaroos_and_narwhals.text)
执行后会输出:
tree kangaroos
tree kangaroos and narwhals
(9)使用 SpaCy 加载了英语语言模型 "en_core_web_sm",然后对文本 "This is another example text." 进行处理,生成了文档对象 doc。接着,通过列表推导式提取了文档中每个标记的粗粒度词性标签,并将结果存储在 pos_tag 列表中。最终,打印了包含粗粒度词性标签的列表。
import spacy
nlp = spacy.load("en_core_web_sm")
doc = nlp("This is another example text.")
# 粗粒度的词性标签
[pos_tag for pos_tag in [token.pos_ for token in doc]]
执行后会输出:
['DET', 'VERB', 'DET', 'DET', 'NOUN', 'NOUN', 'PUNCT']
(10)使用 SpaCy 加载了英语语言模型 "en_core_web_sm",然后对文本 "Microsoft News delivers news from the most popular and trusted publishers." 进行处理,生成了文档对象 doc。接着,通过遍历文档中的每个标记,打印了每个标记的原始文本 (token.text)、词形还原后的文本 (token.lemma_) 以及粗粒度的词性标签 (token.pos_)。这样可以查看每个标记的基本信息,包括原始文本、词形还原和词性标签。
import spacy
nlp = spacy.load("en_core_web_sm")
doc = nlp("Microsoft News delivers news from the most popular and trusted publishers.")
for token in doc:
print("{0} – {1} – {2}".format(token.text, token.lemma_, token.pos_))
执行后会输出:
Microsoft – Microsoft – PROPN
News – News – PROPN
delivers – deliver – VERB
news – news – NOUN
from – from – ADP
the – the – DET
most – most – ADV
popular – popular – ADJ
and – and – CCONJ
trusted – trusted – ADJ
publishers – publisher – NOUN
. – . – PUNCT
(11)SpaCy 可以通过内置模型的帮助,在文档中识别不同的命名实体,实现命名实体识别(NER)的标准方式是使用 doc.ents。请看下面的代码,使用 SpaCy 加载了英语语言模型 "en_core_web_sm",然后对文本 "Steve Jobs founded Apple" 进行处理,生成了文档对象 doc。接着,通过列表推导式提取了文档中每个命名实体跨度的文本和标签,将结果以列表的形式存储在 [(ent.text, ent.label_) for ent in doc.ents] 中。最终,打印了包含命名实体跨度文本和标签的列表。这样可以查看文档中被识别的命名实体及其对应的标签。
import spacy
nlp = spacy.load("en_core_web_sm")
doc = nlp("Steve Jobs founded Apple")
# 命名实体跨度的文本和标签
[(ent.text, ent.label_) for ent in doc.ents]
执行后会输出:
[('Steve Jobs', 'PERSON'), ('Apple', 'ORG')]
(12)使用 SpaCy 加载了英语语言模型 "en_core_web_sm",然后对文本 "It’s official: Apple is the first U.S. public company to reach a $1 trillion market value" 进行处理,生成了文档对象 doc。接着,通过遍历文档中的每个命名实体 (doc.ents),打印了每个命名实体的文本和标签,这样可以查看文档中被识别的命名实体及其对应的标签。
import spacy
nlp = spacy.load("en_core_web_sm")
doc = nlp("It’s official: Apple is the first U.S. public company to reach a $1 trillion market value")
for entity in doc.ents:
print(entity.text + ' ==== ' + entity.label_)
执行后会输出:
Apple ==== ORG
first ==== ORDINAL
U.S. ==== GPE
$1 trillion ==== MONEY
(13)使用 SpaCy 加载了英语语言模型 "en_core_web_sm",然后对文本 "It’s official: Apple is the first U.S. public company to reach a $1 trillion market value" 进行处理,生成了文档对象 doc。接着,通过遍历文档中的每个标记,获取了每个标记的文本、词性标签和依存关系标签,并以格式化的方式打印输出。
import spacy
text = "It’s official: Apple is the first U.S. public company to reach a $1 trillion market value"
# 处理文本
doc = nlp(text)
for token in doc:
# 获取标记的文本、词性标签和依存关系标签
token_text = token.text
token_pos = token.pos_
token_dep = token.dep_
# 仅用于格式化输出
print('{:<12}{:<10}{:<10}'.format(token_text, token_pos, token_dep))
执行后会输出:
It PRON nsubj
’s PROPN ROOT
official NOUN acomp
: PUNCT punct
Apple PROPN nsubj
is VERB ROOT
the DET det
first ADJ amod
U.S. PROPN nmod
public ADJ amod
company NOUN attr
to PART aux
reach VERB relcl
a DET det
$ SYM quantmod
1 NUM compound
trillion NUM nummod
market NOUN compound
value NOUN dobj
(14)使用 SpaCy 加载了英语语言模型 "en_core_web_sm",然后对文本 "New iPhone X release date leaked as Apple reveals pre-orders by mistake" 进行处理,生成了文档对象 doc。接着,通过遍历文档中的每个命名实体 (doc.ents),打印了每个命名实体的文本和标签。
import spacy
text = "New iPhone X release date leaked as Apple reveals pre-orders by mistake"
# 处理文本
doc = nlp(text)
# 遍历命名实体
for entity in doc.ents:
# 打印命名实体的文本和标签
print(entity.text, entity.label_)
执行后会输出:
Apple ORG
(15)使用 SpaCy 加载英语语言模型 "en_core_web_sm",然后对文本 "New iPhone X release date leaked as Apple reveals pre-orders by mistake" 进行处理,生成了文档对象 doc。接着,通过遍历文档中的每个命名实体 (doc.ents),打印了每个命名实体的文本和标签。然后,通过 doc[1:3] 获取了文档中 "iPhone X" 的跨度,并打印了该跨度的文本。这样可以查看文档中被识别的命名实体及其对应的标签,以及通过文档索引获取的实体跨度。
import spacy
text = "New iPhone X release date leaked as Apple reveals pre-orders by mistake"
# 处理文本
doc = nlp(text)
# 遍历命名实体
for entity in doc.ents:
# 打印命名实体的文本和标签
print(entity.text, entity.label_)
# 获取 "iPhone X" 的跨度
iphone_x = doc[1:3]
# 打印跨度的文本
print('Missing entity:', iphone_x.text)
执行后会输出:
Apple ORG
Missing entity: iPhone X