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

Nem*_*emo 4 python spacy

以下链接显示了如何添加自定义实体规则,其中实体跨越多个令牌。执行此操作的代码如下:

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])
Run Code Online (Sandbox Code Playgroud)

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

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

但我收到了这个错误:

---------------------------------------------------------------------------
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']
Run Code Online (Sandbox Code Playgroud)

我的问题是:

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

  2. 使用大写字母作为标签是否是最佳实践(例如,ruler.add_patterns([{"label": "animal", "pattern": a}])应该使用大写字母ruler.add_patterns([{"label": "ANIMAL", "pattern": a}])代替?

DBa*_*ker 8

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

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

Run Code Online (Sandbox Code Playgroud)

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

print(nlp.pipe_names)
# ['tagger', 'parser', 'rulerPlants', 'rulerAnimals']
Run Code Online (Sandbox Code Playgroud)

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

rulerAll = EntityRuler(nlp)
rulerAll.add_patterns(rulerAnimals.patterns)
rulerAll.add_patterns(rulerPlants.patterns)
Run Code Online (Sandbox Code Playgroud)

最后,关于您关于实体标签最佳实践的问题,通常的做法是使用用大写字母书写的缩写(请参阅Spacy NER 文档),例如 ORG、LOC、PERSON 等。

编辑以下问题:

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

2)编程中有“简单胜于复杂”的思想。(见这里)。关于什么构成更简单的解决方案可能存在一些主观性。我认为具有较少组件的处理管道更简单(即包含两个实体标尺的管道对我来说似乎更复杂)。但是,这取决于您在分析、可调整性等方面的需求。如本解决方案的第一部分中所述,对于您拥有多个不同的实体标尺可能会更简单。最好让 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}])
Run Code Online (Sandbox Code Playgroud)

上面显示的用于构造 ruleAll 的其他代码旨在说明我们如何查询实体标尺以获取已添加到其中的模式列表。在实践中,我们会直接构造 ruleAll,而无需先构造 rulePlant 和 ruleAnimal。除非我们想单独测试和分析这些(rulerPlant 和 ruleAnimal)。