中文分词
中文分词(Chinese Word Segmentation) 指的是将一个汉字序列切分成一个一个单独的词。分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。jieba 是目前Python中文分词组件之一。
特点
支持四种分词模式:
- 精确模式,试图将句子最精确地切开,适合文本分析;
- 全模式,把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义;
- 搜索引擎模式,在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。
- paddle模式,利用PaddlePaddle深度学习框架,训练序列标注(双向GRU)网络模型实现分词。同时支持词性标注。paddle模式使用需安装paddlepaddle-tiny,pip install paddlepaddle-tiny==1.6.1。目前paddle模式支持jieba v0.40及以上版本。jieba v0.40以下版本,请升级jieba,pip install jieba --upgrade 。
支持繁体分词
支持自定义词典
算法
- 基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图 (DAG);
- 采用了动态规划查找最大概率路径, 找出基于词频的最大切分组合;
- 对于未登录词,采用了基于汉字成词能力的 HMM 模型,使用了 Viterbi 算法;
安装
- 安装jieba分词库:pip install jieba,并通过import jieba引入;
- 如果需要使用paddle模式下的分词和词性标注功能,请先安装paddlepaddle-tiny,pip install paddlepaddle-tiny==1.6.1;
主要功能
- jieba.cut 方法接受四个输入参数: 需要分词的字符串;cut_all 参数用来控制是否采用全模式;HMM 参数用来控制是否使用 HMM 模型;use_paddle 参数用来控制是否使用paddle模式下的分词模式,paddle模式采用延迟加载方式,通过enable_paddle接口安装paddlepaddle-tiny,并且import相关代码;
- jieba.cut_for_search 方法接受两个参数:需要分词的字符串;是否使用 HMM 模型。该方法适合用于搜索引擎构建倒排索引的分词,粒度比较细;
- 待分词的字符串可以是 unicode 或 UTF-8 字符串、GBK 字符串。注意:不建议直接输入 GBK 字符串,可能无法预料地错误解码成 UTF-8;
- jieba.cut 以及 jieba.cut_for_search 返回的结构都是一个可迭代的 generator,可以使用 for 循环来获得分词后得到的每一个词语(unicode),或者用
jieba.lcut 以及 jieba.lcut_for_search 直接返回 list - jieba.Tokenizer(dictionary=DEFAULT_DICT) 新建自定义分词器,可用于同时使用不同词典。jieba.dt 为默认分词器,所有全局分词相关函数都是该分词器的映射。
案例一
需求:简单实现分词功能。
# -*- encoding: utf-8 -*-
import jieba
jieba.enable_paddle()
strs = ["我来到北京清华大学"]
for str in strs:
seg_list = jieba.cut(str, use_paddle=True)
print('Paddle模式: ' + '/'.join(list(seg_list)))
seg_list = jieba.cut(str, cut_all=False)
print('精确模式: ' + '/'.join(list(seg_list)))
Paddle enabled successfully…
Paddle模式: 我/来到/北京清华大学
精确模式: 我/来到/北京/清华大学
案例二
需求:对人民日报语料完成切词,并通过统计每个词出现的概率,计算信息熵。
# -*- encoding: utf-8 -*--
import os
import jieba
import codecs
from collections import Counter
import math
def calEntropy(use_paddle=False):
parent_path = './example/1946年05月'
file_list = os.listdir(parent_path)
all_words = []
for file in file_list:
path = os.path.join(parent_path, file)
#path = parent_path + '/' + file
with codecs.open(path, 'rb', 'utf-8') as fr:
for line in fr.readlines():
line = line.replace('\n', '').replace(' ', '').replace('\t', '') # 特殊字符过滤
# 将文章所有的切词合并到all_seg中
all_words += jieba.cut(line, use_paddle=use_paddle)
#print('/'.join(list(all_words)))
wordSize = len(all_words) # 词库大小
word_dict = Counter(all_words) # 将所有的分词转换为Counter统计计算
entropy = 0.0
for word in word_dict:
word_number = word_dict[word]
prob = word_number / wordSize # 计算每个分词的频率
entropy -= prob * math.log(prob, 2) # 计算信息熵
return entropy
print('[paddle精确模式]统计词库的信息熵:%.3f' %(calEntropy(use_paddle=True)))
print('[jieba精确模式]统计词库的信息熵:%.3f' %(calEntropy(use_paddle=False)))
[paddle精确模式]统计词库的信息熵:10.830
[jieba精确模式]统计词库的信息熵:10.830
思考
1)思考一下,假设输入一个词表里面含有N个词,输入一个长度为M的句子,那么最大前向匹配的计算复杂度是多少?
答:时间复杂度最坏情况O(m^2),最好的情况O(m)。
2)给定一个句子,如何计算里面有多少种分词候选,你能给出代码实现吗?
根据最大前向匹配算法,其分词候选代码实现如下:
# -*- encoding: utf-8 -*-
line = "南京市长江大桥为南京第一长大桥"
dic = ['南京', '南京市', '市长', '长江', '大桥', '长江大桥', '第一']
dic = set(dic)
matchSize = 5 # 词语的最大批量长度
words = [] # 记录已经分好的词
idx = 0
epoch = 0
while idx < len(line):
matchFlag = False
epoch += 1
print('进行第%d轮匹配.' %(epoch))
for i in range(matchSize, 0, -1):
char = line[idx:idx+i]
print('从[%s]最左边选择候选子串[%s]' %(line[idx:], char))
if char in dic:
words.append(char)
matchFlag = True
break # 匹配成功直接退出该次循环,进行下一轮matchSize匹配
# 如果未在词典中找到任何词,直接当做未登录词记录在words中
if not matchFlag:
words.append(line[idx])
i = 1
idx += i
print('基于最大前向匹配算法分词结果:', ' / '.join(words))
进行第1轮匹配.
从[南京市长江大桥为南京第一长大桥]最左边选择候选子串[南京市长江]
从[南京市长江大桥为南京第一长大桥]最左边选择候选子串[南京市长]
从[南京市长江大桥为南京第一长大桥]最左边选择候选子串[南京市]
进行第2轮匹配.
从[长江大桥为南京第一长大桥]最左边选择候选子串[长江大桥为]
从[长江大桥为南京第一长大桥]最左边选择候选子串[长江大桥]
进行第3轮匹配.
从[为南京第一长大桥]最左边选择候选子串[为南京第一]
从[为南京第一长大桥]最左边选择候选子串[为南京第]
从[为南京第一长大桥]最左边选择候选子串[为南京]
从[为南京第一长大桥]最左边选择候选子串[为南]
从[为南京第一长大桥]最左边选择候选子串[为]
进行第4轮匹配.
从[南京第一长大桥]最左边选择候选子串[南京第一长]
从[南京第一长大桥]最左边选择候选子串[南京第一]
从[南京第一长大桥]最左边选择候选子串[南京第]
从[南京第一长大桥]最左边选择候选子串[南京]
进行第5轮匹配.
从[第一长大桥]最左边选择候选子串[第一长大桥]
从[第一长大桥]最左边选择候选子串[第一长大]
从[第一长大桥]最左边选择候选子串[第一长]
从[第一长大桥]最左边选择候选子串[第一]
进行第6轮匹配.
从[长大桥]最左边选择候选子串[长大桥]
从[长大桥]最左边选择候选子串[长大桥]
从[长大桥]最左边选择候选子串[长大桥]
从[长大桥]最左边选择候选子串[长大]
从[长大桥]最左边选择候选子串[长]
进行第7轮匹配.
从[大桥]最左边选择候选子串[大桥]
基于最大前向匹配算法分词结果: 南京市 / 长江大桥 / 为 / 南京 / 第一 / 长 / 大桥
4万+

被折叠的 条评论
为什么被折叠?



