添加具有空格的多个实体标尺(ValueError:'Entity_Ruler'管道中已存在)

2022-05-15 00:00:00 python spacy

问题描述

以下link说明如何在实体跨越多个令牌的情况下添加自定义实体规则。执行此操作的代码如下:

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])

我尝试添加另一个自定义实体标尺,如下所示:

flower = ["rose", "tulip", "african daisy"]
ruler = EntityRuler(nlp)
for f in flower:
    ruler.add_patterns([{"label": "flower", "pattern": f}])
nlp.add_pipe(ruler)

但我收到此错误:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-47-702f460a866f> in <module>()
      4 for f in flower:
      5     ruler.add_patterns([{"label": "flower", "pattern": f}])
----> 6 nlp.add_pipe(ruler)
      7 

~AppDataLocalContinuumanaconda3libsite-packagesspacylanguage.py in add_pipe(self, component, name, before, after, first, last)
    296                 name = repr(component)
    297         if name in self.pipe_names:
--> 298             raise ValueError(Errors.E007.format(name=name, opts=self.pipe_names))
    299         if sum([bool(before), bool(after), bool(first), bool(last)]) >= 2:
    300             raise ValueError(Errors.E006)

ValueError: [E007] 'entity_ruler' already exists in pipeline. Existing names: ['tagger', 'parser', 'ner', 'entity_ruler']

我的问题是:

  1. 如何添加另一个自定义实体标尺?

  2. 标签使用大写字母是否是最佳做法(例如,应该使用ruler.add_patterns([{"label": "ANIMAL", "pattern": a}])而不是ruler.add_patterns([{"label": "animal", "pattern": a}])


解决方案

您可以通过更改名称将另一个自定义实体标尺添加到您的管道中(以避免名称冲突)。以下是要说明的一些代码,但请阅读下面的备注:

import spacy
from spacy.pipeline import EntityRuler
nlp = spacy.load('en_core_web_sm', disable = ['ner'])
rulerPlants = EntityRuler(nlp, overwrite_ents=True)
flowers = ["rose", "tulip", "african daisy"]
for f in flowers:
    rulerPlants.add_patterns([{"label": "flower", "pattern": f}])
animals = ["cat", "dog", "artic fox"]
rulerAnimals = EntityRuler(nlp, overwrite_ents=True)
for a in animals:
    rulerAnimals.add_patterns([{"label": "animal", "pattern": a}])

rulerPlants.name = 'rulerPlants'
rulerAnimals.name = 'rulerAnimals'
nlp.add_pipe(rulerPlants)
nlp.add_pipe(rulerAnimals)

doc = nlp("cat and artic fox, plant african daisy")
for ent in doc.ents:
    print(ent.text , '->', ent.label_)

#output:
#cat -> animal
#artic fox -> animal
#african daisy -> flower

我们可以验证管道是否包含两个实体标尺:

print(nlp.pipe_names)
# ['tagger', 'parser', 'rulerPlants', 'rulerAnimals']

备注:我建议使用更简单、更自然的方法制作一个新的实体标尺,其中包含两个实体标尺的规则:

rulerAll = EntityRuler(nlp)
rulerAll.add_patterns(rulerAnimals.patterns)
rulerAll.add_patterns(rulerPlants.patterns)
最后,关于您提出的有关实体标签的最佳实践的问题,通常使用大写字母的缩写(参见Spacy NER documentation) 例如ORG、LOC、Person等。

编辑以下问题:

1)如果您不需要Spacy的默认命名实体识别(NER),那么我建议禁用它,因为这将加速计算并避免干扰(请参阅关于此的讨论here)。禁用NER不会导致意外的下游结果(只是不会为默认实体LOC、ORG、Person等标记您的文档)。

2)编程中有这样一种想法:"简单比复杂好。"(see here)。关于构成更简单的解决方案的内容可能存在一些主观性。我认为组件较少的处理流水线更简单(即包含两个实体标尺的流水线在我看来更复杂)。但是取决于您在配置、适应性等方面的需求。它可能更简单,因为您有几个不同的实体标尺,如本解决方案的第一部分所述。如果Spacy的作者能给出他们对这两种不同设计选择的看法,那就太好了。

3)自然可以直接创建上面的单实体标尺:

rulerAll = EntityRuler(nlp, overwrite_ents=True)
for f in flowers:
    rulerAll.add_patterns([{"label": "flower", "pattern": f}])
for a in animals:
    rulerAll.add_patterns([{"label": "animal", "pattern": a}])
上面为构造rulerAll而显示的其他代码旨在说明如何向实体标尺查询已添加到其中的模式列表。在实践中,我们会直接构造标尺,而不需要首先构造标尺植物和标尺动物。除非我们想要单独测试和分析它们(rulerPlants和rulerAnimal)。

相关文章