使用spaCy添加多个EntityRuler(ValueError:“ entity_ruler”已存在于管道中)

时间:2019-08-17 11:52:48

标签: 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 

~\AppData\Local\Continuum\anaconda3\lib\site-packages\spacy\language.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}])

1 个答案:

答案 0 :(得分:2)

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

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的其他代码旨在说明如何查询实体标尺以获取已添加到其的模式列表。在实践中,我们将直接构造RulerAll,而无需先构造RulerPlant和RulerAnimal。除非我们想分别测试和分析这些文件(rulerPlant和RulerAnimal)。