有没有办法关闭 Spacy 中特定的内置标记化规则?

Chu*_*Yat 2 nlp tokenize spacy

Spacy 自动将诸如“dont”和“don't”之类的单词缩写标记为“do”和“nt”/“n't”。例如,像“我不明白”这样的句子将被标记为:[“I”, “do”, “nt”, “understand”]

我知道这在许多 NLP 任务中通常很有帮助,但是有没有办法在 Spacy 中抑制这种特殊的标记化规则,从而使结果变为[“I”、“dont”、“understand”]

这是因为我正在尝试评估我的自定义 Spacy NER 模型的性能(BIO 标记方案的 f1-score),并且输入句子中的标记数量与谓词标记标记数量的不匹配导致了我的问题评估代码如下:

  • 输入(3 个标记):[("I", "O"), ("dont", "O"), ("understand", "O")]

  • 预测(4 个标记):[("I", "O"), ("do", "O"), ("nt", "O"), ("understand", "O")]

当然,如果有人对 Spacy 中的顺序标记任务执行评估有任何建议(可能类似于seqeval包,但与 Spacy 的标记格式更兼容),我们也将不胜感激。

Ine*_*ani 5

特殊情况的标记化规则在tokenizer_exceptions.py相应的语言数据中定义(请参阅此处的英语“nt”缩写)。当您创建新的Tokenizer时,可以通过参数传入这些特殊情况规则rules

方法 1:具有不同特殊情况规则的自定义分词器

因此,您可以为您的用例做的一件事是使用相同的前缀、后缀和中缀规则重建英语Tokenizer,但仅使用一组经过过滤的分词器例外。分词器异常由字符串作为键控,因此您可以删除条目"dont"以及您需要的任何其他内容。但是,代码非常冗长,因为您正在重建整个标记生成器:

from spacy.lang.en import English
from spacy.lang.punctuation import TOKENIZER_PREFIXES, TOKENIZER_SUFFIXES, TOKENIZER_INFIXES                                                                          
from spacy.lang.en import TOKENIZER_EXCEPTIONS  
from spacy.tokenizer import Tokenizer
from spacy.util import compile_prefix_regex, compile_suffix_regex, compile_infix_regex

prefix_re = compile_prefix_regex(TOKENIZER_PREFIXES).search
suffix_re = compile_suffix_regex(TOKENIZER_SUFFIXES).search
infix_re = compile_infix_regex(TOKENIZER_INFIXES).finditer
filtered_exc = {key: value for key, value in TOKENIZER_EXCEPTIONS.items() if key not in ["dont"]} 

nlp = English()
tokenizer = Tokenizer(
    nlp.vocab, 
    prefix_search=prefix_re, 
    suffix_search=suffix_re, 
    infix_finditer=infix_re, 
    rules=filtered_exc
)
nlp.tokenizer = tokenizer
doc = nlp("I dont understand")
Run Code Online (Sandbox Code Playgroud)

方法 2:事后合并(或拆分)令牌

另一种方法是保持标记化不变,但在顶部添加规则,以便随后将某些标记合并在一起,以匹配所需的标记化。这显然在运行时会更慢,但它可能更容易实现和推理,因为您可以从“哪些令牌当前是分离的但应该是一个?”的角度来处理它。为此,您可以使用基于规则的Matcher重新标记将匹配的标记重新合并在一起。从 spaCy v2.1 开始,它还支持拆分(如果相关的话)。

from spacy.lang.en import English
from spacy.matcher import Matcher

nlp = English()
matcher = Matcher(nlp.vocab)
patterns = [[{"LOWER": "do"}, {"LOWER": "nt"}]]
matcher.add("TO_MERGE", None, *patterns)

doc = nlp("I dont understand")
matches = matcher(doc)
with doc.retokenize() as retokenizer:
    for match_id, start, end in matches:
        span = doc[start:end]
        retokenizer.merge(span)
Run Code Online (Sandbox Code Playgroud)

上面的模式将匹配两个标记(每个标记一个字典),其小写形式为“do”和“nt”(例如“DONT”、“dont”、“DoNt”)。您可以向模式添加更多字典列表来描述其他标记序列。对于每一场比赛,您可以创建一个标记Span并将其合并为一个标记。为了使这个逻辑更加优雅,您还可以将其包装为自定义管道组件nlp,这样当您调用文本时它就会自动应用。