Z.S.K.'s Records

python中文分词器-结巴分词

由于工作需要用到对中文进行分词,但碍于中文不同英文,英文只有26个字母组成,中文汉字常见的就有几千个,各种不同形式的组合,而且还有些生僻字,所以中文分词这块一起比较复杂,需要大量的语料库做训练.中科院的ICTCLAS,哈工大的ltp,东北大学的NIU Parser是学术界著名的中文分词器,但由于不开源,想要更好的二次开始很困难,jieba分词是python写成的一个比较有名的中文分词开源库,比较强大,其github地址**在这里**

Jieba

该项目的作者其实挺有意思,对结巴这个词反其道用之,想想还确实比较符合中文分词,jieba分词支持3种模式及可以自定义词典,而且还支持繁体中文的分词,还是比较强大的

采用算法

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

3种分词模式

  1. 精确模式: 试图将句子最精确地切开,适合文本分析
  2. 全模式: 把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义
  3. 搜索引擎模式: 在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词

这里使用的是第一种模式,把文本分解成日常生活中常用的词是一种比较常用的适用场景,而全模式则会把文本所有的词都分开,速度快但存在歧义.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#encoding=utf-8
import jieba

seg_list = jieba.cut("我来到北京清华大学", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list)) # 全模式

seg_list = jieba.cut("我来到北京清华大学", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精确模式

seg_list = jieba.cut("他来到了网易杭研大厦") # 默认是精确模式
print(", ".join(seg_list))

seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所,后在日本京都大学深造") # 搜索引擎模式
print(", ".join(seg_list))

#输出
#全模式: 我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学
#
#精确模式: 我/ 来到/ 北京/ 清华大学
#
#新词识别:他, 来到, 了, 网易, 杭研, 大厦 (此处,“杭研”并没有在词典中,但是也被Viterbi算法识别出来了)
#
#搜索引擎模式: 小明, 硕士, 毕业, 于, 中国, 科学, 学院, 科学院, 中国科学院, 计算, 计算所, 后, 在, 日本, 京都, 大学, 日本京都大学, 深造

自定义词典

在python中import jieba使用时,会引用包里自带的字典,但是允许我们添加自定义的词典,以便包含 jieba 词库里没有的词,jieba也提倡自己添加词典,以便提高具体场景下分词正确率,自带的词典文件在jieba包的dict.txt

词典的格式也很简单: 每一行分三部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒,在词频省略时使用自动计算的能保证分出该词的词频

常用函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#载入自定义词典文件路径
jieba.load_userdict(file_name)
#提取出现频率最高的TopK词及权重
tags = jieba.analyse.extract_tags(content, topK=topK, withWeight=withWeight)
#提取出现频率最高的TopK词
tags = jieba.analyse.extract_tags(content, topK=topK)
#对字符串进行分词,cut_all为True时采用全模式,为False时使用精确模式,该方法直接返回list对象
fenci = jieba.lcut(rline,cut_all=True,HMM=False)
#同上,返回的为一个可迭代的generator,可使用for循环输出每一个词
fenci = jieba.lcut(rline,cut_all=True,HMM=False)
#搜索引擎模式
seg_list = jieba.cut_for_search(rline,HMM=False)
#程序中动态添加或删除词典
jieba.add_word(word, freq=None, tag=None)
jieba.del_word(word)
#词性标注,返回的对象中包含分词后的词及该词所属词性
word = jieba.posseg.cut(rline)

商品名称替换为TopK

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
with open(fileone, "r", encoding="GBK") as f:
for line in f:
#统计文件总行数
line_total = line_total+1
#到文件末尾退出
if not line:
break
#按0_07分隔符分隔字段(请将_换成x)
rline = re.split("[]", line, 1)
#商品名称只保留汉字
rline[0] = re.sub(pattern,"",rline[0])
#过滤商品名称为空的行
if (rline[0]):
#分词
fenci = jieba.lcut(rline[0])
#以topK为准比较分词结果,如果存在于topK,则返回第一个分词替换原有的商品名称(topK越排前频率越高)
for x in range(len(tags)):
if tags[x] in fenci:
rline[0] = tags[x]
break
else:
continue
#如果所有的分词都不存在topk中则商品名称不变
line_fmt = rline[0] + "[]" + rline[1]
f1.write(line_fmt)
else:
#统计处理后商品名称为空行数
blk_total = blk_total+1
return fileone,line_total,blk_total

参考文章:

转载请注明原作者: 周淑科(https://izsk.me)


 wechat
Scan Me To Read on Phone
I know you won't do this,but what if you did?