转载来源:https://blog.csdn.net/u013510838/article/details/81738431
上篇文章我们分析了自然语言处理,特别是中文处理中,分词的几个主要难点。为了解决这些难点,我们提出了基于字符串匹配的算法和基于统计的分词算法。针对当前的几种分词引擎,我们对其分词准确度和速度进行了评估。jieba分词作为一个开源项目,在准确度和速度方面均不错,是我们平时常用的分词工具。本文将对jieba分词的使用方法以及原理进行讲解,便于我们在理解jieba分词原理的同时,加深对前文讲解的分词难点和算法的理解。
jieba分词是一个开源项目,地址为 https://github.com/fxsjy/jieba 它在分词准确度和速度方面均表现不错。其功能和用法如下。
支持三种分词模式
- 精确分词,试图将句子最精确的切开,适合文本分析
- 全模式,把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义
- 搜索引擎模式,在精确模式基础上,对长词进行再次切分,提高recall,适合于搜索引擎。
输出为
主要是为了解决新词问题,jieba分词基于HMM算法会自动识别新词,但用户如果能直接给出新词,则准确率会更高。
使用起来很简单,我们先创建一个文件,比如user_dict.txt,其中每一行代表一个新词,分别为词语,词频,词性。如下:
然后在代码中分词前,加载这个自定义词典即可。
加载自定义词典的分词效果:
关键词提取,将文本中最能表达文本含义的词语抽取出来,有点类似于论文的关键词或者摘要。关键词抽取可以采取:
- 有监督学习:文本作为输入,关键词作为标注,进行训练得到模型。此方法难点在于需要大量人工标注
- 无监督学习:先抽取出候选词,对每个候选词打分,取出前K个分值高的作为最后的关键词。jieba分词实现了基于TF-IDF和基于TextRank的关键词抽取算法。
基于TF-IDF的关键词抽取算法,目标是获取文本中词频高,也就是TF大的,且语料库其他文本中词频低的,也就是IDF大的。这样的词可以作为文本的标志,用来区分其他文本。
__基于TextRank的关键词抽取算法__步骤为,
- 先将文本进行分词和词性标注,将特定词性的词(比如名词)作为节点添加到图中。
- 出现在一个窗口中的词语之间形成一条边,窗口大小可设置为2~10之间,它表示一个窗口中有多少个词语。
- 对节点根据入度节点个数以及入度节点权重进行打分,入度节点越多,且入度节点权重大,则打分高。
- 然后根据打分进行降序排列,输出指定个数的关键词。
利用jieba.posseg模块来进行词性标注,会给出分词后每个词的词性。词性标示兼容ICTCLAS 汉语词性标注集,可查阅网站 https://www.cnblogs.com/chenbjin/p/4341930.html
将文本按行分隔后,每行由一个jieba分词进程处理,之后进行归并处理,输出最终结果。这样可以大大提高分词速度。
jieba采用延迟加载方式,import jieba 时不会立刻加载jieba词典,使用时才开始加载。如果想提前加载和初始化,可以手动触发
我们分词的jieba源码版本为0.39。代码结构如下
主要的模块如下
- 基本API的封装,在Tokenizer类中,相当于一个外观类。如cut del_word add_word enable_parallel initialize 等
- 基于字符串匹配的分词算法,包含一个很大很全的词典,即dict.txt文件
- 基于统计的分词算法,实现了HMM隐马尔科夫模型。jieba分词使用了字符串分词和统计分词,结合了二者的优缺点。
- 关键词提取,实现了TFIDF和TextRank两种无监督学习算法
- 词性标注,实现了HMM隐马尔科夫模型和viterbi算法
jieba分词综合了基于字符串匹配的算法和基于统计的算法,其分词步骤为
- 初始化。加载词典文件,获取每个词语和它出现的词数
- 切分短语。利用正则,将文本切分为一个个语句,之后对语句进行分词
- 构建DAG。通过字符串匹配,构建所有可能的分词情况的有向无环图,也就是DAG
- 构建节点最大路径概率,以及结束位置。计算每个汉字节点到语句结尾的所有路径中的最大概率,并记下最大概率时在DAG中对应的该汉字成词的结束位置。
- 构建切分组合。根据节点路径,得到词语切分的结果,也就是分词结果。
- HMM新词处理:对于新词,也就是dict.txt中没有的词语,我们通过统计方法来处理,jieba中采用了HMM隐马尔科夫模型来处理。
- 返回分词结果:通过yield将上面步骤中切分好的词语逐个返回。yield相对于list,可以节约存储空间。
词典是基于字符串匹配的分词算法的关键所在,决定了最终分词的准确度。jieba词典dict.txt是jieba作者采集了超大规模的语料数据,统计得到的。有5M,包含349,046条词语。每一行对应一个词语,包含词语 词数 词性三部分。如下
初始化时,先加载词典文件dict.txt,遍历每一行,生成词语-词数的键值对和总词数,并将生成结果保存到cache中,下次直接从cache中读取即可。代码如下,删除了无关的log打印。只需要看关键节点代码即可,不提倡逐行逐行阅读代码,最重要的是理解代码执行的主要流程和关键算法。
初始化可以简单理解为,读取词典文件,构建词语-词数键值对,方便后面步骤中查词典,也就是字符串匹配。
使用汉字正则,切分出连续的汉字和英文字符,形成一段段短语。可以理解为以空格 逗号 句号为分隔,将输入文本切分为一个个短语,之后会基于一个个短语来分词。代码如下
- 首先进行将语句转换为UTF-8或者GBK。
- 然后根据用户指定的模式,设置cut的真正实现。
- 然后根据正则,将输入文本分为一个个语句。
- 最后遍历语句,对每个语句单独进行分词。
下面我们来分析默认模式,也就是精确模式下的分词过程。先来看__cut_DAG方法。
主体步骤如下
- 得到语句的有向无环图DAG
- 动态规划构建Route,计算从语句末尾到语句起始,DAG中每个节点到语句结束位置的最大路径概率,以及概率最大时节点对应词语的结束位置
- 遍历每个节点的Route,组装词语组合。
- 如果词语不在字典中,也就是新词,使用HMM隐马尔科夫模型进行分割
- 通过yield将词语逐个返回。
下面我们来看构建DAG的过程。先遍历一个个切分好的短语,对这些短语来进行分词。首先要构建短语的有向无环图DAG。查词典进行字符串匹配的过程中,可能会出现好几种可能的切分方式,将这些组合构成有向无环图,如下图所示
可以看到,构成了两条路径:
- 有意/见/分歧
- 有/意见/分歧
DAG中记录了某个词的开始位置和它可能的结束位置。开始位置作为key,结束位置是一个list。比如位置0的DAG表达为
{0: [1, 2]}, 也就是说0位置为词的开始位置时,1,2位置都有可能是词的结束位置。上面语句的完整DAG为
DAG构建过程的代码如下:
中文一般形容词在前面,而相对来说更关键的名词和动词在后面。考虑到这一点,jieba中对语句,从右向左反向计算路径的最大概率,这个类似于逆向最大匹配。每个词的概率 = 字典中该词的词数 / 字典总词数。对于上图构建每个节点的最大路径概率的过程如下:
对应代码如下
从节点0开始,按照步骤4中构建的最大路径概率以及结束位置,取出节点0的结束位置,构成词语。如果是单字词语,则直接通过yield返回。如果词语在字典中,也直接通过yield返回。如果词语不在字典中,也就是新词,则需要通过HMM隐马尔科夫模型来分割。节点0处理完毕,则跳到下一个词语的开始处进行处理,直至到达语句末尾。
代码参见__cut_DAG(),也就是主体流程代码。
对于新词,也就是dict.txt中没有的词语,我们通过统计方法来处理,jieba中采用了HMM隐马尔科夫模型。回顾下HMM的五要素:观测序列,隐藏序列,发射概率,起始概率,转移概率。由这五大要素可以对我们的短语建模。
- 观测序列:语句本身,我们能看见的。
- 隐藏序列:由BMES构成的分词标注序列,上篇文章详细讲解了的。每个汉字可以由BMES来进行标注,B表示词语的开始,M词语中间,E词语结束,S单字词语。比如“有意见分歧”对应的标注有两种,为SBEBE和BESBE,分别对应分词序列“有/意见/分歧”和“有意/见/分歧”。
- 发射概率:隐藏值到观测值的概率,比如S是汉字“有”的概率。
- 起始概率:隐藏值起始概率,起始只能是B或者S,通过语料大规模训练可以得到B和S作为起始的概率。结果为{‘B’: 0.769, ‘E’: 0, ‘M’: 0, ‘S’: 0.231},可见起始为B的概率要远大于S,这也符合我们通常情况。
- 转移概率:隐藏值之间转移的概率,比如B->E, 表示为P(E|B), B->M, 表示为p(M|B)
通过语料大规模训练,可以得到发射概率,起始概率和转移概率。通过viterbi算法,可以得到概率最大的隐藏序列,也就是 BEMS标注序列,通过BEMS就可以对语句进行分词了。我们观察发现,新词被分成二字词语的概率很大。
转移概率在prob_trans.py中,如下
起始概率在prob_start.py中,如下
隐马尔科夫模型处理代码主要为
viterbi算法的代码如下
以上就是本篇文章【自然语言处理2 -- jieba分词用法及原理】的全部内容了,欢迎阅览 ! 文章地址:http://dfvalve.xrbh.cn/quote/5420.html 行业 资讯 企业新闻 行情 企业黄页 同类资讯 网站地图 返回首页 迅博思语资讯移动站 http://keant.xrbh.cn/ , 查看更多