如何添加特定的子字符串以在spaCy中进行标记化?

问题描述

我正在使用spaCy标记字符串,并且该字符串可能包含特定的子字符串。如果存在子字符串,则我希望spaCy将子字符串视为令牌,而不管它有任何其他规则。我想保留所有其他规则。这可能吗?

一个具体的例子,假设感兴趣的子字符串是'banana';我希望将'I like bananabread.'标记['I','like','banana','bread','.']

我从这里去哪里(请记住,我想保持其余令牌生成器规则的完整性)?我尝试将'banana'添加到前缀,后缀和中缀,但没有成功。

解决方法

将字符串添加为前缀,后缀和中缀应该可以,但是根据所使用的spacy版本,测试时可能会遇到缓存错误。此错误已在v2.2 +中修复。

使用spacy v2.3.2:

import spacy
nlp = spacy.load("en_core_web_sm")

text = "I like bananabread."
assert [t.text for t in nlp(text)] == ['I','like','bananabread','.']

prefixes = ("banana",) + nlp.Defaults.prefixes
suffixes = ("banana",) + nlp.Defaults.suffixes
infixes = ("banana",) + nlp.Defaults.infixes

prefix_regex = spacy.util.compile_prefix_regex(prefixes)
suffix_regex = spacy.util.compile_suffix_regex(suffixes)
infix_regex = spacy.util.compile_infix_regex(infixes)

nlp.tokenizer.prefix_search = prefix_regex.search
nlp.tokenizer.suffix_search = suffix_regex.search
nlp.tokenizer.infix_finditer = infix_regex.finditer

assert [t.text for t in nlp(text)]  == ['I','banana','bread','.']

(在v2.1或更早版本中,令牌生成器自定义仍然适用于新加载的nlp,但是如果您已经使用nlp管道处理了一些文本,然后修改了设置,的错误是它将使用缓存中存储的令牌化,而不是新设置。)

,

令牌化发生在spaCy管道的开头,因此您应该先对文本进行预处理。

我编写了一个使用正则表达式填充复合词中的子字符串的函数:

import re

text = 'I eat bananas and bananabread at the bookstore.'

def separate_compound_toks(text):
    anti_compound = sorted(['banana','store'])
    anti_compound = "|".join(t.lower() for t in anti_compound)
    # pad word from end
    pattern_a = re.compile(r'(?i)({sub})(?=[a-z]{{3,}})'.format(sub=anti_compound))
    text = re.sub(pattern_a,r'\1 ',text)
    # pad word from beginning
    pattern_b = re.compile(r'(?i)(?<![^a-z])({sub})'.format(sub=anti_compound))
    text = re.sub(pattern_b,r' \1',text)
    return text


import spacy
nlp = spacy.load("en_core_web_sm")
 
doc = nlp(separate_compound_toks(text))
print([tok.text for tok in doc])
# ['I','eat','bananas','and','at','the','book','store','.']