自然语言处理2 -- jieba分词用法及原理

   日期:2024-12-27    作者:23gox 移动:http://mip.riyuangf.com/mobile/quote/73277.html


转载来源: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的关键词抽取算法__步骤为

  1. 先将文本进行分词和词性标注,将特定词性的词(比如名词)作为节点添加到图中。
  2. 出现在一个窗口中的词语之间形成一条边,窗口大小可设置为2~10之间,它表示一个窗口中有多少个词语。
  3. 对节点根据入度节点个数以及入度节点权重进行打分,入度节点越多,且入度节点权重大,则打分高。
  4. 然后根据打分进行降序排列,输出指定个数的关键词。
 
 

利用jieba.posseg模块来进行词性标注,会给出分词后每个词的词性。词性标示兼容ICTCLAS 汉语词性标注集,可查阅网站 https://www.cnblogs.com/chenbjin/p/4341930.html

 
 

将文本按行分隔后,每行由一个jieba分词进程处理,之后进行归并处理,输出最终结果。这样可以大大提高分词速度。

 
 
 
 
 
 

jieba采用延迟加载方式,import jieba 时不会立刻加载jieba词典,使用时才开始加载。如果想提前加载和初始化,可以手动触发

 
 
 
  1. 基本API的封装,在Tokenizer类中,相当于一个外观类。如cut del_word add_word enable_parallel initialize 等
  2. 基于字符串匹配的分词算法,包含一个很大很全的词典,即dict.txt文件
  3. 基于统计的分词算法,实现了HMM隐马尔科夫模型。jieba分词使用了字符串分词和统计分词,结合了二者的优缺点。
  4. 关键词提取,实现了TFIDF和TextRank两种无监督学习算法
  5. 词性标注,实现了HMM隐马尔科夫模型和viterbi算法

jieba分词综合了基于字符串匹配的算法和基于统计的算法,其分词步骤为

  1. 初始化。加载词典文件,获取每个词语和它出现的词数
  2. 切分短语。利用正则,将文本切分为一个个语句,之后对语句进行分词
  3. 构建DAG。通过字符串匹配,构建所有可能的分词情况的有向无环图,也就是DAG
  4. 构建节点最大路径概率,以及结束位置。计算每个汉字节点到语句结尾的所有路径中的最大概率,并记下最大概率时在DAG中对应的该汉字成词的结束位置。
  5. 构建切分组合。根据节点路径,得到词语切分的结果,也就是分词结果。
  6. HMM新词处理:对于新词,也就是dict.txt中没有的词语,我们通过统计方法来处理,jieba中采用了HMM隐马尔科夫模型来处理。
  7. 返回分词结果:通过yield将上面步骤中切分好的词语逐个返回。yield相对于list,可以节约存储空间。

词典是基于字符串匹配的分词算法的关键所在,决定了最终分词的准确度。jieba词典dict.txt是jieba作者采集了超大规模的语料数据,统计得到的。有5M,包含349,046条词语。每一行对应一个词语,包含词语 词数 词性三部分。如下

 

初始化时,先加载词典文件dict.txt,遍历每一行,生成词语-词数的键值对和总词数,并将生成结果保存到cache中,下次直接从cache中读取即可。代码如下,删除了无关的log打印。只需要看关键节点代码即可,不提倡逐行逐行阅读代码,最重要的是理解代码执行的主要流程和关键算法。

 

初始化可以简单理解为,读取词典文件,构建词语-词数键值对,方便后面步骤中查词典,也就是字符串匹配。

使用汉字正则,切分出连续的汉字和英文字符,形成一段段短语。可以理解为以空格 逗号 句号为分隔,将输入文本切分为一个个短语,之后会基于一个个短语来分词。代码如下

 
  1. 首先进行将语句转换为UTF-8或者GBK。
  2. 然后根据用户指定的模式,设置cut的真正实现。
  3. 然后根据正则,将输入文本分为一个个语句。
  4. 最后遍历语句,对每个语句单独进行分词。

下面我们来分析默认模式,也就是精确模式下的分词过程。先来看__cut_DAG方法。

 

主体步骤如下

  1. 得到语句的有向无环图DAG
  2. 动态规划构建Route,计算从语句末尾到语句起始,DAG中每个节点到语句结束位置的最大路径概率,以及概率最大时节点对应词语的结束位置
  3. 遍历每个节点的Route,组装词语组合。
  4. 如果词语不在字典中,也就是新词,使用HMM隐马尔科夫模型进行分割
  5. 通过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算法的代码如下

 
 

通过yield将上面步骤中切分好的词语逐个返回。yield相对于list,可以节约存储空间。


特别提示:本信息由相关用户自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。


举报收藏 0评论 0
0相关评论
相关最新动态
推荐最新动态
点击排行
{
网站首页  |  关于我们  |  联系方式  |  使用协议  |  隐私政策  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  鄂ICP备2020018471号