面向特定问题的开源算法管理和推荐(十)

 2021SC@SDUSC


系列文章目录

(一)组内分工情况

(二)任务一爬虫部分代码分析(上)

(三)任务一爬虫部分代码分析(下)

(四)任务一数据集统计代码分析

(五)任务二及PKE模型解读

(六)PKE模型使用一

(七)PKE模型使用二

(八)PKE代码分析一

(九)PKE代码分析二

(十)PKE代码分析三

目录

系列文章目录

前言

一、readers.py

(一)class RawTextReader(Reader):

  spacy介绍

  (二)class MinimalCoreNLPReader(Reader):

二、langcodes.py

总结


前言

承接上文,继续对以下代码进行分析


一、readers.py

pke 模块的读取器 

结构如下,包含了3个类和4个类外函数

(一)class RawTextReader(Reader):

原始文本的阅读器

包含了2个函数

1.def __init__(self, language=None):#RawTextReader 的构造函数。

参数:
            language (str):要处理的文本的语言。

        self.language = language

        if language is None:
            self.language = 'en'

2.def read(self, text, **kwargs):#读取输入文件并使用 spacy 进行预处理。

         Spacy 模型选择:默认情况下,此函数将加载最接近 `language` 参数的 spacy 模型('fr' 语言将加载链接到 'fr' 或任何 'fr_core_web_*' 可用模型的 spacy 模型)。 为了选择将要使用的模型,请通过 `spacy_model` 参数提供一个预加载的模型,或者将希望使用的模型链接到相应的语言代码 `python3 -m spacy link spacy_model lang_code`。

     参数:
             text (str):要预处理的原始文本。
             max_length (int): spacy 的单个文本中的最大字符数(对于 spacy<3 兼容性,从 spacy v3 开始,长文本应拆分为较小的部分),默认为 1,000,000 个字符(1mb)。
             spacy_model (model): 一个已经加载的 spacy 模型。

        spacy_model = kwargs.get('spacy_model', None)

        if spacy_model is None:
            try:
                spacy_model = spacy.load(str2spacy(self.language),
                                         disable=['ner', 'textcat', 'parser'])
            except OSError:
                logging.warning('No spacy model for \'{}\' language.'.format(self.language))
                logging.warning('Falling back to using english model. There might '
                    'be tokenization and postagging errors. A list of available '
                    'spacy model is available at https://spacy.io/models.'.format(
                        self.language))
                spacy_model = spacy.load(str2spacy('en'),
                                         disable=['ner', 'textcat', 'parser'])
            if int(spacy.__version__.split('.')[0]) < 3:
                sentencizer = spacy_model.create_pipe('sentencizer')
            else:
                sentencizer = 'sentencizer'
            spacy_model.add_pipe(sentencizer)
            if 'max_length' in kwargs and kwargs['max_length']:
                spacy_model.max_length = kwargs['max_length']

        spacy_model = fix_spacy_for_french(spacy_model)
        spacy_doc = spacy_model(text)

        sentences = []
        for sentence_id, sentence in enumerate(spacy_doc.sents):
            sentences.append({
                "words": [token.text for token in sentence],
                "lemmas": [token.lemma_ for token in sentence],
                # FIX : This is a fallback if `fix_spacy_for_french` does not work
                "POS": [token.pos_ or token.tag_ for token in sentence],
                "char_offsets": [(token.idx, token.idx + len(token.text))
                                 for token in sentence]
            })

        doc = Document.from_sentences(
            sentences, input_file=kwargs.get('input_file', None), **kwargs)

        return doc

spacy介绍

spaCy处理文本的过程是模块化的,当调用nlp处理文本时,spaCy首先将文本标记化以生成Doc对象,然后,依次在几个不同的组件中处理Doc,这也称为处理管道。语言模型默认的处理管道依次是:tagger、parser、ner等,每个管道组件返回已处理的Doc,然后将其传递给下一个组件。

一,加载语言模型

spaCy使用的语言模型是预先训练的统计模型,能够预测语言特征,对于英语,共有en_core_web_sm、en_core_web_md和en_core_web_lg三种语言模型,还有一种语言模型:en,需要以管理员权限运行以下命令来安装en模型:

python -m spacy download en

使用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)

 

(二)class MinimalCoreNLPReader(Reader):

最小 CoreNLP XML 解析器

包含两个函数

1.def __init__(self):#构造函数

self.parser = etree.XMLParser()

下面介绍etree的情况

import xml.etree.ElementTree as etree

简介
xml.etree.ElementTree模块实现了一个简单而高效的API用于解析和创建XML数据。xml.etree.ElementTree模块对于恶意构造的数据是不安全的。如果您需要解析不受信任或未经验证的数据,请参阅XML漏洞。
参考文献:https://docs.python.org/3.6/library/xml.etree.elementtree.html
 

2.def read(self, path, **kwargs):

        sentences = []
        tree = etree.parse(path, self.parser)
        for sentence in tree.iterfind('./document/sentences/sentence'):
            # get the character offsets
            starts = [int(u.text) for u in
                      sentence.iterfind("tokens/token/CharacterOffsetBegin")]
            ends = [int(u.text) for u in
                    sentence.iterfind("tokens/token/CharacterOffsetEnd")]
            sentences.append({
                "words": [u.text for u in
                          sentence.iterfind("tokens/token/word")],
                "lemmas": [u.text for u in
                           sentence.iterfind("tokens/token/lemma")],
                "POS": [u.text for u in sentence.iterfind("tokens/token/POS")],
                "char_offsets": [(starts[k], ends[k]) for k in
                                 range(len(starts))]
            })
            sentences[-1].update(sentence.attrib)

        doc = Document.from_sentences(sentences, input_file=path, **kwargs)

        return doc

(三)def fix_spacy_for_french(nlp):

修复https://github.com/boudinfl/pke/issues/115.
对于某些特殊的标记化情况,spacy不分配“pos”字段。
取自https://github.com/explosion/spaCy/issues/5179.

 (四)def list_linked_spacy_models():

读取SPACY/data并返回链接名称列表

spacy_data = os.path.join(spacy.info(silent=True)['Location'], 'data')
    linked = [d for d in os.listdir(spacy_data) if os.path.islink(os.path.join(spacy_data, d))]
   

(五)def list_downloaded_spacy_models():

扫描PYTHONPATH以查找spacy模型

二、langcodes.py

摘自https://github.com/LuminosoInsight/langcodes/blob/master/langcodes/data/language-subtag-registry.txt

def parse_language_names(s):
    return [i.strip().lower() for i in s.split(',')]

LANGUAGE_CODES = {
    item['code']: parse_language_names(item['name'])
    for item in LANGUAGES
}

LANGUAGE_CODE_BY_NAME = {}

for k, v in LANGUAGE_CODES.items():
    for name in v:
        LANGUAGE_CODE_BY_NAME[name] = k

总结

本文分析了readers.py和 langcodes.py的代码,并对spacy的语言模型进行了介绍,从下一篇开始将分析具体模型的相关原理及代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值