前言
通过前面博文的学习,我们知道在处理自然语言之时,肯定会用到语料库。目前,常用的语料库有PKU(人民日报语料库),MSR(微软亚洲研究院语料库)。而因为PKU是1998年时公开的,随着时代的发展,其分词早已经不大符合大众习惯。加之其手动编写有很多失误。所以,我们将在后面的博文中使用MSR语料库。
语料库就绪之后,就可以开始训练了。相信接触过机器学习的读者,或多或少都对训练并不陌生。训练指的是,给定样本集估计模型参数的过程。对于自然语言处理来说,训练指的是统计N元语法频次。有了频次,通过极大似然估计以及平滑策略,我们就可以估计任意句子的概率分布,就得到语言模型。本篇主要讲解一元语法与二元语法。
加载语料库
在处理自然语言时,我们首先要做的是加载语料库。而HanLP库提供了许多封装好的工具,对于这些通过空格符分割的分词语料库来讲,可以利用HanLP库提供的CorpusLoader.convert2SentencelList加载。
具体代码如下:
if __name__ == "__main__": CorpusLoader = SafeJClass('com.hankcs.hanlp.corpus.document.CorpusLoader') sents = load_cws_corpus(r"E:\ProgramData\Anaconda3\Lib\site-packages\pyhanlp\static\data\test\icwb2-data\gold\msr_test_gold.utf8") for sent in sents: print(sent)
运行之后,效果如下:
这里,每一个List都是个语句,且都已经分词成功。
统计语法
一元语法其实就是单词,如果把单词与词频写成纯文本格式,就得到了一部词频词典。有些语料库含有人工标注的词性,因此词典格式还是要支持词性,这也就是HanLP词典格式的涉及初衷。
在HanLP中,一元语法的统计功能由DictionaryMaker提供,二元语法统计由NatureDictionaryMaker提供。通过NatureDictionaryMaker类,我们可以统计一元语法模型,与二元语法模型。
详细代码实现如下:
if __name__ == "__main__": NatureDictionaryMaker = SafeJClass('com.hankcs.hanlp.corpus.dictionary.NatureDictionaryMaker') CorpusLoader = SafeJClass('com.hankcs.hanlp.corpus.document.CorpusLoader') sents = load_cws_corpus(r"E:\ProgramData\Anaconda3\Lib\site-packages\pyhanlp\static\data\test\icwb2-data\gold\msr_test_gold.utf8") for sent in sents: for word in sent: word.setLabel("n") maker = NatureDictionaryMaker() maker.compute(sents) maker.saveTxtTo("123")
运行之后,我们会在同级的项目目录下生成3个文件:
123.txt:一元语法模型
123.ngram.txt:二元语法模型
123.tr.txt:词性标注
具体效果如下:
如上图所示,它们之间用空格分开,分别代表的意思是:单词,词性,词性频次。还有图片没截取到的符号“末##末“,这个符号代表句子结尾,”始##始“代表句子开头。
而二元模型中,@符号分割开二元语法中的两个单词,空格后面是二元语法的频次。
下面,我们再来把该二元模型的搭建转换成通用的函数,毕竟本人用MSR语料库,并不代表所有人都用。通用的方法可以导入任意词典搭建语法模型。
def load_cws_corpus(corpus_path): CorpusLoader = SafeJClass('com.hankcs.hanlp.corpus.document.CorpusLoader') return CorpusLoader.convert2SentenceList(corpus_path) #传入语料库路径以及导出模型的名称路径 def train_model(corpus_path,model_path): NatureDictionaryMaker = SafeJClass('com.hankcs.hanlp.corpus.dictionary.NatureDictionaryMaker') sents = load_cws_corpus(corpus_path) for sent in sents: for word in sent: word.setLabel("n") maker = NatureDictionaryMaker() maker.compute(sents) maker.saveTxtTo(model_path)