jieba源代码分析 您所在的位置:网站首页 比亚迪水陆两栖汽车叫什么名字 jieba源代码分析

jieba源代码分析

2024-02-19 08:22| 来源: 网络整理| 查看: 265

2021SC@SDUSC 2021SC@SDUSC

在之前的TextRank算法的源代码解析中,我们所做的流程的第一步就是进行分词,使用到了cut函数(默认使用精确模式),但其实cut函数共有四种模式——精确模式、搜索引擎模式、全模式、paddle模式。 2021SC@SDUSC 2021SC@SDUSC python分词主要是基于动态规划和其构成的前缀词典。 虽然同样都是分词,但四种模式在分词的精细度方面有所差异,比如看下面的例子:

import jieba #默认精确模式 instance=jieba.cut("黄包车师傅总是吆喝两声接活,街边的糖炒栗子香气像雪在落") print("精确模式:\t" + '/'.join(list(instance))) #搜索引擎模式 instance=jieba.cut_for_search("黄包车师傅总是吆喝两声接活,街边的糖炒栗子香气像雪在落") print("搜索引擎模式:\t" + '/'.join(list(instance))) #全模式 instance=jieba.cut("黄包车师傅总是吆喝两声接活,街边的糖炒栗子香气像雪在落",cut_all=True) print("全模式:\t" + '/'.join(list(instance))) #paddle模式 instance=jieba.cut("黄包车师傅总是吆喝两声接活,街边的糖炒栗子香气像雪在落",use_paddle=True) print("paddle模式:\t" + '/'.join(list(instance)))

同样的句子,使用四种不同的模式,输出如下: 在这里插入图片描述 精确模式: 黄包车/师傅/总是/吆喝/两声/接活/,/街边/的/糖/炒栗子/香气/像/雪/在/落 搜索引擎模式: 包车/黄包车/师傅/总是/吆喝/两声/接活/,/街边/的/糖/栗子/炒栗子/香气/像/雪/在/落 全模式: 黄包车/包车/车师/师傅/总是/吆喝/两声/接活/,/街边/的/糖/炒栗子/栗子/香气/像/雪/在/落 paddle模式: 黄包车/师傅/总是/吆喝/两声/接活/,/街边/的/糖/炒栗子/香气/像/雪/在/落 我们可以看到,精确模式就是我们平常所用,分词精准; 搜索引擎模式,提供了更多分词可能,可以用于搜索引擎的词语匹配; 全模式则是分词的全部可能,最为全面; paddle模式分词结果近似于精准模式,平时所用较少,利用PaddlePaddle深度学习框架,训练序列标注(双向GRU)网络模型实现分词。同时支持词性标注。

jieba分词基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图 (DAG);采用了动态规划查找最大概率路径, 找出基于词频的最大切分组合;对于未登录词,采用了基于汉字成词能力的 HMM 模型,使用了 Viterbi 算法。

关于cut函数的代码存放在jieba/_init_中,从这篇博客开始,我们会对这个文件中的代码逐行分析。

首先看第一部分代码如下:

出现了re.compile,是有关分词的正则表达式的判定,例如出现TF-IDF,jieba将其分为两个词TF和IDF,还是看作一个词,便与此相关。

在此处,re_han_default是基于正则表达式进行汉字判断,符合此表达式,则被判定为是汉字。

#正则表达式,判断是否是汉字 re_han_default = re.compile("([\u4E00-\u9FD5a-zA-Z0-9+#&\._%\-]+)", re.U) #正则表达式,符号匹配问题相关 re_skip_default = re.compile("(\r\n|\s)", re.U)

然后便是jieba库非常有用的一个类Tokenizer,四种不同的分词模式的函数均在此类中定义。

那么在分词前第一步,便是构建分词需要的前缀词典, 前缀词典中会保存每个词以及其词频和词性。 代码如下:

def gen_pfdict(self, f):# f 为词典文件 lfreq = {} # 空字典 ltotal = 0 f_name = resolve_filename(f) # 返回f的文件名 for lineno, line in enumerate(f, 1):# lineno:序号,line:f的内容,逐行读取f的内容 try: line = line.strip().decode('utf-8') word, freq = line.split(' ')[:2] freq = int(freq) lfreq[word] = freq ltotal += freq # 词频总数 # 获取前缀,若在词典中则跳过,不在则加入词典,且置频数为0 for ch in xrange(len(word)): wfrag = word[:ch + 1] if wfrag not in lfreq: lfreq[wfrag] = 0 except ValueError: raise ValueError( 'invalid dictionary entry in %s at Line %s: %s' % (f_name, lineno, line)) f.close() #关闭文件f return lfreq, ltotal # 返回前缀词典,词汇总数

代码具体分析解释可见旁注,

# 从前缀字典中获得此的出现次数 def gen_word_freq(self, word): if word in self.FREQ: #在词典中,返回词 return self.FREQ[word] else: return 0

我们分析代码可知其返回了一个字典lfreq,形式为{word:freq},其中不仅有原词典中的词和频数,还有原词典中词语的前缀,其频数为0,这就是前缀词典,根据此词典,我们就可以生成所有词语可能的有向无环图,有向无环图的代码详解见下一篇博客。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有