4

我正在尝试在本体世界中使用 SpaCy 进行实体上下文识别。我是使用 SpaCy 的新手,只是在玩初学者。

我使用ENVO Ontology作为我的“模式”列表来创建实体识别字典。简单来说,数据是一个 ID (CURIE) 和它对应的实体的名称及其类别。

我的示例数据的屏幕截图: 在此处输入图像描述

以下是我的初始代码的工作流程:

  • 创建模式和术语

    # Set terms and patterns
    terms = {}
    patterns = []
    for curie, name, category in envoTerms.to_records(index=False):
        if name is not None:
            terms[name.lower()] = {'id': curie, 'category': category}
            patterns.append(nlp(name))

  • 设置自定义管道

    @Language.component('envo_extractor')
    def envo_extractor(doc):
        
        matches = matcher(doc)
        spans = [Span(doc, start, end, label = 'ENVO') for matchId, start, end in matches]
        doc.ents = spans
        
        for i, span in enumerate(spans):
            span._.set("has_envo_ids", True)
            for token in span:
                token._.set("is_envo_term", True)
                token._.set("envo_id", terms[span.text.lower()]["id"])
                token._.set("category", terms[span.text.lower()]["category"])
        
        return doc
    
    # Setter function for doc level
    def has_envo_ids(self, tokens):
        return any([t._.get("is_envo_term") for t in tokens])

##EDIT: #################################################################
    def resolve_substrings(matcher, doc, i, matches):
        # Get the current match and create tuple of entity label, start and end.
        # Append entity to the doc's entity. (Don't overwrite doc.ents!)
        match_id, start, end = matches[i]
        entity = Span(doc, start, end, label="ENVO")
        doc.ents += (entity,)
        print(entity.text)
#########################################################################
  • 实现自定义管道

    nlp = spacy.load("en_core_web_sm")
    matcher = PhraseMatcher(nlp.vocab)
    #### EDIT: Added 'on_match' rule ################################
    matcher.add("ENVO", None, *patterns, on_match=resolve_substrings)
    nlp.add_pipe('envo_extractor', after='ner')

管道看起来像这样


    [('tok2vec', <spacy.pipeline.tok2vec.Tok2Vec at 0x7fac00c03bd0>),
     ('tagger', <spacy.pipeline.tagger.Tagger at 0x7fac0303fcc0>),
     ('parser', <spacy.pipeline.dep_parser.DependencyParser at 0x7fac02fe7460>),
     ('ner', <spacy.pipeline.ner.EntityRecognizer at 0x7fac02f234c0>),
     ('envo_extractor', <function __main__.envo_extractor(doc)>),
     ('attribute_ruler',
      <spacy.pipeline.attributeruler.AttributeRuler at 0x7fac0304a940>),
     ('lemmatizer',
      <spacy.lang.en.lemmatizer.EnglishLemmatizer at 0x7fac03068c40>)]

  • 设置扩展

    # Set extensions to tokens, spans and docs
    Token.set_extension('is_envo_term', default=False, force=True)
    Token.set_extension("envo_id", default=False, force=True)
    Token.set_extension("category", default=False, force=True)
    Doc.set_extension("has_envo_ids", getter=has_envo_ids, force=True)
    Doc.set_extension("envo_ids", default=[], force=True)
    Span.set_extension("has_envo_ids", getter=has_envo_ids, force=True)

现在,当我运行文本“组织培养”时,它会抛出一个错误:


    nlp('tissue culture')


    ValueError: [E1010] Unable to set entity information for token 0 which is included in more than one span in entities, blocked, missing or outside.

我知道为什么会发生错误。这是因为在 ENVO 数据库中有 2 个“组织培养”短语的条目,如下所示:

在此处输入图像描述

理想情况下,我希望根据文本中出现的短语来标记适当的 CURIE。我该如何解决这个错误?

我的 SpaCy 信息:


    ============================== Info about spaCy ==============================
    
    spaCy version    3.0.5                         
    Location         *irrelevant*
    Platform         macOS-10.15.7-x86_64-i386-64bit
    Python version   3.9.2                         
    Pipelines        en_core_web_sm (3.0.0)   

  
4

3 回答 3

6

现在可能有点晚了,但是补充了Sofie VL的回答,对于任何可能仍然对此感兴趣的人来说,我(另一个 spaCy 新手,大声笑)为摆脱重叠跨度所做的事情,如如下:

import spacy
from spacy.util import filter_spans

# [Code to obtain 'entity']...
# 'entity' should be a list, i.e.:
# entity = ["Carolina", "North Carolina"]

pat_orig = len(entity)
filtered = filter_spans(ents) # THIS DOES THE TRICK
pat_filt =len(filtered)
doc.ents = filtered

print("\nCONVERSION REPORT:")
print("Original number of patterns:", pat_orig)
print("Number of patterns after overlapping removal:", pat_filt)

值得一提的是,我目前使用的是最新版本的 spaCy,v3.1.1。此外,仅当您实际上不介意删除重叠跨度时,它才会起作用,但如果您这样做,那么您可能想看看这个线程。有关“filter_spans”的更多信息在这里

此致。

于 2021-08-19T15:16:20.647 回答
3

spacyv3 开始,您可以使用doc.spans来存储可能重叠的实体。不支持此功能doc.ents

所以你有两个选择:

  • 实现一个on_match回调,在使用结果设置之前过滤掉匹配器的结果doc.ents。快速浏览一下您的代码(以及后来的编辑),我认为resolve_substrings实际上并没有解决冲突?理想情况下,该on_match函数应检查是否与现有实体存在冲突,并决定保留哪些。
  • 如果这适用于您的用例,请使用doc.spans而不是。doc.ents
于 2021-04-15T16:00:44.400 回答
0

不要加载模型,而是尝试使用并检查nlp = spacy.load("en_core_web_sm")初始化 nlp 对象。nlp = English()希望它有效。

本质上,替换

nlp = spacy.load("en_core_web_sm")

nlp = English()
于 2021-09-27T11:07:01.887 回答