SpaCy:为包含在多个跨度中的令牌设置实体信息

问题描述

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

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

我的示例数据的屏幕截图:

enter image description here

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

  • 创建模式和术语

    # 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,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,end = matches[i]
        entity = Span(doc,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",force=True)
    Token.set_extension("category",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",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 个条目,如下所示:

enter image description here

理想情况下,我希望根据文本中出现的短语标记适当的 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)   

  

解决方法

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

所以你有两个选择:

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...