知识图谱入门——10:使用 spaCy 进行命名实体识别(NER)的进阶应用:基于词袋的实体识别与知识抽取

时间:2024-10-06 09:46:16

在构建知识图谱的过程中,如何准确地识别和提取实体是关键。spaCy 提供了强大的命名实体识别(NER)功能,我们可以结合自定义规则和工具来实现更精准的实体抽取。本文将详细探讨如何在 spaCy 中实现自定义实体抽取,包括使用词袋、批量添加模式、加载外部文件、使用自定义组件和结合正则表达式进行复杂匹配。

1. 自定义词袋实体抽取

基于 spaCy 的 EntityRuler,我们可以轻松定义特定短语作为整体实体,而不是将其拆分为多个部分。以下示例展示了如何将“出生于中国北京”处理为一个整体实体。

import spacy
from spacy.pipeline import EntityRuler

# 加载中文模型
nlp = spacy.load("zh_core_web_sm")

# 创建EntityRuler
ruler = EntityRuler(nlp)

# 自定义词袋:将“中国北京”识别为一个整体实体
patterns = [{"label": "GPE", "pattern": "中国北京"}]

# 将模式加入ruler
ruler.add_patterns(patterns)

# 注册并添加EntityRuler到pipeline
nlp.add_pipe("entity_ruler", config={"overwrite_ents": True}, last=True)

# 将自定义的ruler实例添加到 pipeline 中
nlp.get_pipe("entity_ruler").add_patterns(patterns)

# 测试
doc = nlp("李华出生于中国北京,他是个很有名的运动员。")
for ent in doc.ents:
    print(ent.text, ent.label_)

解释

  • 通过上述方式,EntityRuler 被成功注册到 pipeline 中,并且我们能够将模式添加到它的实例中。
  • 使用 config={“overwrite_ents”: True} 参数来确保自定义的模式能够覆盖模型识别的实体。
    在这里插入图片描述

2. 使用词典批量添加模式

当需要添加多个实体模式时,可以使用一个外部词典来批量添加模式,这样可以避免手动逐个添加的繁琐过程。

# 批量添加模式
dictionary = {
    "GPE": ["中国北京", "美国纽约", "法国巴黎"],
    "ORG": ["清华大学", "阿里巴巴", "腾讯"]
}

# 将模式加入EntityRuler
for label, patterns in dictionary.items():
    for pattern in patterns:
        ruler.add_patterns([{"label": label, "pattern": pattern}])

解释

  • 我们可以使用字典结构来批量添加多个模式,每个标签对应多个短语,这样的方式高效且简洁。

3. 基于外部文件加载模式

如果实体模式较多,存储在外部文件中可能更为方便。我们可以将这些模式保存在 JSON 文件中并动态加载。

import json

# 加载模式的外部文件
with open('patterns.json', 'r', encoding='utf-8') as f:
    patterns = json.load(f)

# 将模式加入EntityRuler
ruler.add_patterns(patterns)

外部 JSON 文件示例 (patterns.json)

[
    {"label": "GPE", "pattern": "中国北京"},
    {"label": "ORG", "pattern": "清华大学"},
    {"label": "GPE", "pattern": "美国纽约"}
]

解释

  • 这种方法使得模式的管理更加灵活,可以根据需要随时更新和修改外部文件,而不需要重新编译代码。

4. 使用自定义实体识别组件

在某些情况下,标准的实体识别方法可能无法满足需求。这时可以自定义组件,以实现特定的实体识别逻辑。

import spacy
from spacy.tokens import Span
from spacy.language import Language
from spacy.pipeline import EntityRuler

# 加载中文模型
nlp = spacy.load("zh_core_web_sm")

# 创建EntityRuler
ruler = EntityRuler(nlp)

# 自定义模式:将“中国北京”识别为一个整体实体
patterns = [{"label": "GPE", "pattern": "中国北京"}]

# 将模式加入ruler
ruler.add_patterns(patterns)

# 注册 EntityRuler
nlp.add_pipe("entity_ruler", config={"overwrite_ents": True}, last=True)

# 添加 EntityRuler 的模式
nlp.get_pipe("entity_ruler").add_patterns(patterns)

# 使用装饰器注册自定义实体识别组件
@Language.component("custom_entity_recognition")
def custom_entity_recognition(doc):
    # 在 doc 中识别并标记"运动员"实体
    for token in doc:
        if token.text == "运动员":
            start = token.i
            end = token.i + 1  # 识别"运动员"作为一个实体
            ent = Span(doc, start, end, label="PERSON")
            doc.ents += (ent,)  # 将新实体添加到doc中
    return doc

# 将自定义组件加入pipeline
nlp.add_pipe("custom_entity_recognition", after="entity_ruler")

# 测试文本
doc = nlp("李华出生于中国北京,他是个很有名的运动员。")

# 打印识别到的实体
for ent in doc.ents:
    print(ent.text, ent.label_)

解释

  • 这个自定义组件检查每个 token,如果发现“运动员”,则将其作为一个实体添加到文档中。这种方式允许我们灵活地识别不常见的实体。
    在这里插入图片描述

5. 结合正则表达式进行复杂匹配

对于一些复杂的实体模式,正则表达式可以提供更强大的匹配能力。

import re

# 自定义实体识别组件结合正则表达式
def regex_entity_recognition(doc):
    text = doc.text
    pattern = r'出生于(.*?)'
    matches = re.findall(pattern, text)
    for match in matches:
        start = text.index(match)
        end = start + len(match)
        ent = Span(doc, start, end, label="PLACE")
        doc.ents += (ent,)
    return doc

解释

  • 该组件使用正则表达式查找“出生于”后面的地方,并将其作为一个实体识别出来。这种方法适用于动态匹配复杂文本中的模式。

通过以上五种方法,我们可以在 spaCy 中实现灵活的实体抽取和匹配,进一步提高知识图谱构建的准确性和效率。后续博客,我们将探讨如何结合 BERT 等模型进行更复杂的知识抽取任务。