问题描述
我正在使用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','.']