如何通过规则合并 spaCy 中的实体

How to merge entities in spaCy via rules

我想使用 spaCy 3 en_core_web_lg 中的一些实体,但将它标记为 'ORG' 的一些实体替换为 'ANALYTIC',因为它处理我的 3 个字符代码想使用 'P&L' 和 'VaR' 作为组织。该模型具有 DATE 实体,我可以保留这些实体。我已经阅读了所有文档,看起来我应该能够使用 EntityRuler,语法如下,但我没有任何进展。我现在已经接受了 2-3 次培训,阅读了所有的用法和 API 文档,但我只是没有看到任何工作代码示例。我收到各种不同的错误消息,比如我需要装饰器或其他。主啊,真的那么难吗?

我的代码:

analytics = [
    [{'LOWER':'risk'}],
    [{'LOWER':'pnl'}],
    [{'LOWER':'p&l'}],
    [{'LOWER':'return'}],
    [{'LOWER':'returns'}]
]


matcher = Matcher(nlp.vocab)
matcher.add("ANALYTICS", analytics)

doc = nlp(text)

# Iterate over the matches
for match_id, start, end in matcher(doc):
    # Create a Span with the label for "ANALYTIC"
    span = Span(doc, start, end, label="ANALYTIC")

    # Overwrite the doc.ents and add the span
    doc.ents = list(doc.ents) + [span]

    # Get the span's root head token
    span_root_head = span.root.head
    # Print the text of the span root's head token and the span text
    print(span_root_head.text, "-->", span.text)

当我的新 'ANALYTIC' 实体跨度与现有 'ORG' 实体跨度发生冲突时,这当然会崩溃。但我不知道如何离线合并这些并将它们放回去,或者使用规则创建我自己的自定义管道。这是来自实体标尺的建议文本。没头绪。

# Construction via add_pipe
ruler = nlp.add_pipe("entity_ruler")

# Construction from class
from spacy.pipeline import EntityRuler
ruler = EntityRuler(nlp, overwrite_ents=True)

所以当你说它“崩溃”时,实际情况是你有冲突的跨度。具体来说,对于 doc.ents,每个标记最多只能在一个范围内。在您的情况下,您可以通过修改此行来解决此问题:

doc.ents = list(doc.ents) + [span]

在这里您包括了旧跨度(您不想要的)和新跨度。如果你得到 doc.ents 而没有旧跨度,这将起作用。

还有其他方法可以做到这一点。在这里,我将使用一个简化的示例,您总是希望更改长度为 3 的项目,但您可以修改它以使用您的特定单词列表或其他内容。

你可以直接修改实体标签,像这样:

for ent in doc.ents:
    if len(ent.text) == 3:
        ent.label_ = "CHECK"
    print(ent.label_, ent, sep="\t")

如果您想使用 EntityRuler,它看起来像这样:

import spacy

nlp = spacy.load("en_core_web_sm")

ruler = nlp.add_pipe("entity_ruler", config={"overwrite_ents":True})

patterns = [
        {"label": "ANALYTIC", "pattern": 
            [{"ENT_TYPE": "ORG", "LENGTH": 3}]}]

ruler.add_patterns(patterns)

text = "P&L reported amazing returns this year."

doc = nlp(text)

for ent in doc.ents:
    print(ent.label_, ent, sep="\t")

还有一件事 - 你没有说明你使用的是什么版本的 spaCy。我在这里使用 spaCy v3。添加管道的方式在 v3 中发生了一些变化。