Python 3.x Spacy,具有跨越多个令牌的实体的匹配器

Python 3.x Spacy,具有跨越多个令牌的实体的匹配器,python-3.x,nlp,spacy,Python 3.x,Nlp,Spacy,我试图创建一个匹配器,在文本中查找否定的自定义实体。对于跨越单个令牌的实体来说,它工作得很好,但是我在尝试捕获跨越多个令牌的实体时遇到了困难 例如,假设我的自定义实体是动物(标记为token.ent\u type=“animal”) [“猫”、“狗”、“阿屈福克斯”](注意最后一个实体有两个单词) 现在我想在文本中找到那些被否定的实体,因此我可以创建一个具有以下模式的简单匹配器: [{'lower':'no'},{'ENT_TYPE':{'REGEX':'animal','OP':'+'}] 例

我试图创建一个匹配器,在文本中查找否定的自定义实体。对于跨越单个令牌的实体来说,它工作得很好,但是我在尝试捕获跨越多个令牌的实体时遇到了困难

例如,假设我的自定义实体是动物(标记为
token.ent\u type=“animal”

[“猫”、“狗”、“阿屈福克斯”]
(注意最后一个实体有两个单词)

现在我想在文本中找到那些被否定的实体,因此我可以创建一个具有以下模式的简单匹配器:

[{'lower':'no'},{'ENT_TYPE':{'REGEX':'animal','OP':'+'}]

例如,我有以下文字:

房子里没有猫,地下室里也没有狐狸

我可以成功捕获
no cat
no artic
,但最后一个匹配不正确,因为完整匹配应该是
no artic fox
。这是由于模式中的
OP:'+'
匹配单个自定义实体而不是两个。如何修改模式以将较长的匹配优先于较短的匹配?

解决方案是使用,以便将每个多令牌实体的各个令牌合并为单个令牌:

import spacy
from spacy.pipeline import EntityRuler
nlp = spacy.load('en_core_web_sm', parse=True, tag=True, entity=True)

animal = ["cat", "dog", "artic fox"]
ruler = EntityRuler(nlp)
for a in animal:
    ruler.add_patterns([{"label": "animal", "pattern": a}])
nlp.add_pipe(ruler)


doc = nlp("There is no cat in the house and no artic fox in the basement")

with doc.retokenize() as retokenizer:
    for ent in doc.ents:
        retokenizer.merge(doc[ent.start:ent.end])


from spacy.matcher import Matcher
matcher = Matcher(nlp.vocab)
pattern =[{'lower': 'no'},{'ENT_TYPE': {'REGEX': 'animal', 'OP': '+'}}]
matcher.add('negated animal', None, pattern)
matches = matcher(doc)


for match_id, start, end in matches:
    span = doc[start:end]
    print(span)

现在输出为:

没有猫
没有阿提克福克斯


使用此解决方案,我甚至不需要向自定义实体添加
…{'OP':'+'}