spaCy 处理文本的过程是模块化的, 当调用 nlp 处理文本时, spaCy 首先将文本标记化以生成 Doc 对象, 然后, 依次在几个不同的组件中处理 Doc, 这也称为处理管道. 语言模型默认的处理管道依次是: tagger,parser,ner 等, 每个管道组件返回已处理的 Doc, 然后将其传递给下一个组件.
一, 加载语言模型
spaCy 使用的语言模型是预先训练的统计模型, 能够预测语言特征, 对于英语, 共有 en_core_web_sm,en_core_web_md 和 en_core_web_lg 三种语言模型, 使用 spacy.load()函数来加载语言模型
spacy.load(name,disable)
其中, name 参数是语言模型的名词, disable 参数是禁用的处理管道列表, 例如, 创建 en_core_web_sm 语言模型, 并禁用 ner:
nlp = spacy.load("en_core_web_sm", disable=['ner'])
语言模型中不仅预先定义了 Language 管道, 还定义了处理文本数据的处理管道(pipeline), 其中分词器是一个特殊的管道, 它是由 Language 管道确定的, 不属于 pipeline.
- {
- "lang": "en",
- "name": "core_web_sm",
- "description": "Example model for spaCy",
- "pipeline": ["tagger", "parser", "ner"]
- }
在加载语言模型 nlp 之后, 可以查看该语言模型预先定义的处理管道, 也就是说, 处理管道依赖于统计模型.
1, 查看 nlp 对象的管道
- >>> nlp.pipe_names
- ['tagger', 'parser', 'ner']
2, 移除 nlp 的管道
nlp.remove_pipe(name)
3, 向 nlp 的处理管道中增加管道
nlp.add_pipe(component, name=None, before=None, after=None, first=None, last=None)
二, 语言管道和分词器管道
Language 管道是一个特殊的管道, 当调用 spacy.load()加载语言模型时, spaCy 自动创建 Lanuage 管道, 用于存储共享的词汇表, 分词规则 (Tokenization Rule) 和文本注释.
分词器管道是跟 Language 管道息息相关的一个管道, 当创建 Language 管道之后, spaCy 根据 Language 管道提供的词汇表来创建分词器. 分词器用于把文本分为单词, 标点符号, 空格等标记, 除了使用默认的分词器之外, spaCy 允许用户根据需要对分词器进行调整:
- from spacy.tokenizer import Tokenizer
- tokenizer = Tokenizer(vocab=nlp.vocab,rules,prefix_search, suffix_search, infix_search, token_match)
参数注释:
vocab: 词汇表
rules:dict 类型, 分词器的特殊规则, 把匹配到特殊规则的单词作为一个 token, 主要是用于设置 token 的注释(annotation);
prefix_search,suffix_search: 类型是 re.compile(string).search
infix_finditer: 类型是 re.compile(string).finditer, 把匹配到这前缀, 后缀或中缀的字符串作为一个 token;
token_match: 返回 boolean 值的函数类型, 把匹配到的字符串识别为一个 token;
在文本处理的过程中, spaCy 首先对文本分词, 原始文本在空格处分割, 类似于 text.split(' '), 然后分词器 (Tokenizer) 从左向右依次处理 token, 在处理 token 时, spaCy 做了两个 check:
是否匹配特殊规则(execption rule)
是否前缀, 中缀或后缀可以分割
一个可选的布尔函数 token_match, 它匹配的字符串不会被拆分, 覆盖以前的规则, 对 URL 或数字之类的东西很有用.
三, 扩展语言
每一种语言都是不同的, 通常充满异常和特殊情况, 尤其是最常见的单词. 其中一些例外是跨语言共享的, 而其他例外则完全具体, 通常非常具体, 需要进行硬编码. spaCy.lang 模块包含所有特定于语言的数据, 以简单的 Python 文件组织, 这使得数据易于更新和扩展.
每一个单独的组件可以在语言模块种导入遍历, 并添加到语言的 Defaults 对象种, 某些组件 (如标点符号规则) 通常不需要自定义, 可以从全局规则中导入. 其他组件, 比如 tokenizer 和 norm 例外, 则非常具体, 会对 spaCy 在特定语言上的表现和训练语言模型产生重大影响.
例如, 导入 English 模块, 查看该模块的帮助:
- from spacy.lang.en import English
- help(English)
通过这些模块来扩展语言, 处理特殊的语法, 通常在分词器 (Tokenizer) 中添加特殊规则和 Token_Match 函数来实现.
1, 向分词器中添加特殊的规则
- import spacy
- from spacy.symbols import ORTH, LEMMA, POS, TAG
- nlp = spacy.load("en_core_web_sm")
- # add special case rule
- special_case = [{
- ORTH: u"gim", LEMMA: u"give", POS: u"VERB"
- }, {
- ORTH: u"me"
- }]
- nlp.tokenizer.add_special_case(u"gimme", special_case)
2, 设置特殊的规则来匹配 token
创建一个自定义的分词器, 使分词把 https 作为一个 token:
- import re
- import spacy
- from spacy.lang.en import English
- def my_en_tokenizer(nlp):
- prefix_re = spacy.util.compile_prefix_regex(English.Defaults.prefixes)
- suffix_re = spacy.util.compile_suffix_regex(English.Defaults.suffixes)
- infix_re = spacy.util.compile_infix_regex(English.Defaults.infixes)
- pattern_re = re.compile(r'^https?://')
- return spacy.tokenizer.Tokenizer(nlp.vocab,
- English.Defaults.tokenizer_exceptions,
- prefix_re.search,
- suffix_re.search,
- infix_re.finditer,
- token_match=pattern_re.match)
在处理文本时调用该分词器, 把匹配到正则的文本作为一个 token 来处理:
- nlp = spacy.load("en_core_web_sm")
- nlp.tokenizer = my_en_tokenizer(nlp)
- doc = nlp(u"Spacy is breaking when combining custom tokenizer's token_match, access https://github.com/explosion/spaCy to get details")
- print([t.text for t in doc])
3, 自定义分词器
预先定义的分词器是按照空格来分词的, 用于可以自定义分词器
- ### customer tokenizer
- class myTokenizer(object):
- def __init__(self, vocab):
- self.vocab = vocab
- def __call__(self, text):
- words=[]
- re_search=my_token_match(text)
- if re_search:
- for start,end in re_search.regs:
- if start>=0 and end>=0:
- words.append(text[start:end])
- text=my_token_replace(text)
- split_words=my_token_split(text)
- print(split_words)
- words.extend([w for w in split_words if w!=''])
- # All tokens 'own' a subsequent space character in this tokenizer
- spaces = [True] * len(words)
- return Doc(self.vocab, words=words, spaces=spaces)
- ### parse the synonyms
- RE_SYNONYMS=parse_synonyms()
- def my_token_match(text):
- global RE_SYNONYMS
- return re.compile(RE_SYNONYMS).search(text)
- def my_token_replace(text):
- global RE_SYNONYMS
- return re.compile(RE_SYNONYMS).sub('',text)
- def my_token_split(text):
- #return re.compile('\s+|\W+|_+').split(text)
- return re.compile('\s+|\\+|_+').split(text)
引用自定义的分词器
- nlp=spacy.load("en_core_web_sm")
- nlp.tokenizer = myTokenizer(nlp.vocab)
参考文档:
- Linguistic Features-Tokenization
- Pipeline https://spacy.io/api/language
- Processing Pipelines https://spacy.io/usage/processing-pipelines
- Adding Languages
来源: https://www.cnblogs.com/ljhdo/p/10762035.html