程序员的资源宝库

网站首页 > gitee 正文

jieba 模块

sanyeah 2024-04-05 13:13:02 gitee 7 ℃ 0 评论

1 特点

  • 支持四种分词模式:

    • 精确模式,试图将句子最精确地切开,适合文本分析;

    • 全模式,把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义;

    • 搜索引擎模式,在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。

    • 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 。 PaddlePaddle 官网

  • 支持繁体分词

  • 支持自定义词典

  • MIT 授权协议

2 算法

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

3 主要功能

3.1 分词

  • jieba.cut

    cut(sentence, cut_all=False, HMM=True, use_paddle=False)

    • sentence:需要分词的字符串;
    • cut_all:参数用来控制是否采用全模式,True 为全模式,False 为精确模式;
    • HMM:参数用来控制是否使用 HMM 模型;
    • use_paddle:参数用来控制是否使用 paddle 模式下的分词模式,paddle 模式采用延迟加载方式,通过 enable_paddle 接口安装 paddlepaddle-tiny,并且 import 相关代码;
  • jieba.cut_for_search

    cut_for_search(sentence, HMM=True)

    • sentence:需要分词的字符串;
    • HMM:是否使用 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 为默认分词器,所有全局分词相关函数都是该分词器的映射。

import numpy as np
import pandas as pd
import jieba

jieba.__version__  # '0.42.1'

jieba.enable_paddle()  # 启动 paddle模式。 0.40版之后开始支持,早期版本不支持

strs = ["我来到北京清华大学","乒乓球拍卖完了","中国科学技术大学"]
for str in strs:
    seg_list = jieba.cut(str, use_paddle=True)
    print("Paddle 模式:" + '/'.join(list(seg_list)))

# 结果
Paddle enabled successfully......
Paddle 模式:我/来到/北京清华大学
Paddle 模式:乒乓球/拍卖/完/了
Paddle 模式:中国科学技术大学
seg_list = jieba.cut("我来到北京清华大学", cut_all=True)  # 从默认词典构建前缀词典
print("全模式:" + "/ ".join(seg_list)) 

# 结果
Building prefix dict from the default dictionary ...
Dumping model to file cache /var/folders/3v/dwdrxl1n1vzf2yj1whmy4v5h0000gn/T/jieba.cache
Loading model cost 1.300 seconds.
Prefix dict has been built successfully.
全模式:我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学
seg_list = jieba.cut("我来到北京清华大学", cut_all=False)  # 返回的结构都是一个可迭代的 generator
print(seg_list)
print("精确模式(默认模式):" + "/ ".join(seg_list)) 

# 结果
<generator object Tokenizer.cut at 0x1453de048>
精确模式(默认模式):我/ 来到/ 北京/ 清华大学
seg_list = jieba.cut_for_search("我来到北京清华大学")
print("搜索引擎模式:" + "/ ".join(seg_list)) 

# 结果
搜索引擎模式:我/ 来到/ 北京/ 清华/ 华大/ 大学/ 清华大学
seg_list = jieba.lcut("我来到北京清华大学", cut_all=False)  # lcut 可以直接返回 list
seg_list

# 结果
['我', '来到', '北京', '清华大学']
seg_list = jieba.cut("他来到了网易杭研大厦")  # 默认是精确模式,此处,“杭研”并没有在词典中,但是也被Viterbi算法识别出来了
print(", ".join(seg_list))

# 结果
他, 来到, 了, 网易, 杭研, 大厦

3.2 添加自定义词典

3.2.1 载入词典

  • 开发者可以指定自己自定义的词典,以便包含 jieba 词库里没有的词。虽然 jieba 有新词识别能力,但是自行添加新词可以保证更高的正确率;

  • 用法: jieba.load_userdict(file_name) # file_name 为文件类对象或自定义词典的路径;

  • 词典格式和 dict.txt 一样,一个词占一行;每一行分三部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒。file_name 若为路径或二进制方式打开的文件,则文件必须为 UTF-8 编码。

  • 词频省略时使用自动计算的能保证分出该词的词频,例如:

创新办 3 i
云计算 5
凱特琳 nz
台中
  • 更改分词器(默认为 jieba.dt)的 tmp_dir 和 cache_file 属性,可分别指定缓存文件所在的文件夹及其文件名,用于受限的文件系统。
  • 范例:
    • 自定义词典:https://github.com/fxsjy/jieba/blob/master/test/userdict.txt

    • 用法示例:https://github.com/fxsjy/jieba/blob/master/test/test_userdict.py

      • 之前: 李小福 / 是 / 创新 / 办 / 主任 / 也 / 是 / 云 / 计算 / 方面 / 的 / 专家 /

      • 加载自定义词库后: 李小福 / 是 / 创新办 / 主任 / 也 / 是 / 云计算 / 方面 / 的 / 专家 /

3.2.2 调整词典

  • 使用 add_word(word, freq=None, tag=None) 和 del_word(word) 可在程序中动态修改词典。

    • 向词典中添加词,freq 和 tag 可以省略。
  • 使用 suggest_freq(segment, tune=True) 可调节单个词语的词频,使其能(或不能)被分出来。

    • segment:期望分割后的词,如何需要词需要作为一个整体,使用一个字符串;
    • tune:如果为 True,调节词频;默认 False。
  • 注意:自动计算的词频在使用 HMM 新词发现功能时可能无效。

  • "通过用户自定义词典来增强歧义纠错能力"

jieba.lcut('如果放到post中将出错。', HMM=False)

jieba.suggest_freq(segment=('中', '将'), tune=True)
jieba.lcut('如果放到post中将出错。', HMM=False)

jieba.lcut('「台中」正确应该不会被切开', HMM=False)

jieba.suggest_freq('台中', True)
jieba.lcut('「台中」正确应该不会被切开', HMM=False)

# 结果
['如果', '放到', 'post', '中将', '出错', '。']
Out[6]:
494
Out[6]:
['如果', '放到', 'post', '中', '将', '出错', '。']
Out[6]:
['「', '台', '中', '」', '正确', '应该', '不会', '被', '切开']
Out[6]:
69
Out[6]:
['「', '台中', '」', '正确', '应该', '不会', '被', '切开']

3.3 关键词提取

3.3.1 基于 TF-IDF 算法的关键词抽取

idf 默认是 jieba 模块已经定义的文本语料库,也可以切换为自定义文本语料库。

  • jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=(), withFlag=False)

    使用 TF-IDF 算法从 sentence 中提取关键词:

    • sentence 为待提取的文本;
    • topK 为返回几个 TF/IDF 权重最大的关键词,默认值为 20;
    • withWeight 为是否一并返回关键词权重值,默认值为 False;
    • allowPOS 仅包括指定词性的词,默认值为空,即不筛选;
    • withFlag:只有当 allowPOS 为空时起作用。如果为 True,返回如 posseg.cut 的 (word, weight) 对的列表,如果为 False,返回词列表;
  • jieba.analyse.TFIDF(idf_path=None) 新建 TFIDF 实例,idf_path 为 IDF 频率文件

import jieba.analyse

text = "线程是程序执行时的最小单位,它是进程的一个执行流,\
        是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,\
        线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。\
        线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。\
        同样多线程也可以实现并发操作,每个请求分配一个线程来处理。"

keywords = jieba.analyse.extract_tags(sentence=text, topK=10)
print("TF-IDF 关键词提取:\n\n", "/".join(keywords))

# 结果
TF-IDF 关键词提取:

 线程/CPU/进程/调度/多线程/程序执行/每个/执行/堆栈/局部变量
# withWeight=True 返回关键词权重值
keywords = jieba.analyse.extract_tags(sentence=text, topK=10, withWeight=True)
keywords

# 结果
[('线程', 1.6092956253903845),
 ('CPU', 0.6896981251673077),
 ('进程', 0.3764666465751923),
 ('调度', 0.32615933279615383),
 ('多线程', 0.2673207240769231),
 ('程序执行', 0.2539909706038462),
 ('每个', 0.22361383583346153),
 ('执行', 0.21377215274192307),
 ('堆栈', 0.212835852075),
 ('局部变量', 0.20620430426153843)]
# allowPOS 指定词性,比如 ['ns', 'n'] 或者 ('ns', 'n')
keywords = jieba.analyse.extract_tags(sentence=text, topK=10, withWeight=True, allowPOS=['ns', 'n'])
keywords

# 结果
[('线程', 3.984922500966667),
 ('进程', 0.9322031248528573),
 ('调度', 0.8076326335904762),
 ('程序执行', 0.6289300224476191),
 ('堆栈', 0.5270221099),
 ('局部变量', 0.5106011343619047),
 ('单位', 0.5105471403419047),
 ('分派', 0.4351668436752381),
 ('资源', 0.25532014137047615),
 ('环境', 0.24676257547285713)]
# withFlag=True 返回关键词权重值
keywords = jieba.analyse.extract_tags(sentence=text, topK=10, withWeight=True, withFlag=False)
keywords

# 结果
[('线程', 1.6092956253903845),
 ('CPU', 0.6896981251673077),
 ('进程', 0.3764666465751923),
 ('调度', 0.32615933279615383),
 ('多线程', 0.2673207240769231),
 ('程序执行', 0.2539909706038462),
 ('每个', 0.22361383583346153),
 ('执行', 0.21377215274192307),
 ('堆栈', 0.212835852075),
 ('局部变量', 0.20620430426153843)]

关键词提取所使用逆向文件频率(即IDF)文本语料库可以切换成自定义语料库的路径。

# 可以先构建一个 TFIDF 实例,再修改实例中的内容,提取关键字
import jieba.analyse

tfidf = jieba.analyse.TFIDF()
tfidf.set_stop_words("../extra_dict/stop_words.txt") 
tfidf.set_idf_path("../extra_dict/idf.txt.big")  
tfidf.extract_tags(sentence)  

# 也可以直接调用函数修改
import jieba.analyse

jieba.analyse.set_stop_words("../extra_dict/stop_words.txt")  
jieba.analyse.set_idf_path("../extra_dict/idf.txt.big")
jieba.analyse.extract_tags(sentence)

3.3.2 基于 TextRank 算法的关键词抽取

  • jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'), withFlag=False) 直接使用,接口相同,注意默认过滤词性。
  • jieba.analyse.TextRank() 新建自定义 TextRank 实例

算法论文:TextRank: Bringing Order into Texts

基本思想:

  1. 将待抽取关键词的文本进行分词
  2. 以固定窗口大小(默认为5,通过span属性调整),词之间的共现关系,构建图
  3. 计算图中节点的PageRank,注意是无向带权图
text = "线程是程序执行时的最小单位,它是进程的一个执行流,\
        是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,\
        线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。\
        线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。\
        同样多线程也可以实现并发操作,每个请求分配一个线程来处理。"

keywords = jieba.analyse.textrank(text, topK=10)
keywords

# 结果
['线程', '进程', '调度', '单位', '操作', '请求', '分配', '允许', '基本', '并发']
keywords = jieba.analyse.textrank(text, topK=10, withWeight=True)
keywords

# 结果
[('线程', 1.0),
 ('进程', 0.4837352620361488),
 ('调度', 0.3595461575195059),
 ('单位', 0.3489332390176574),
 ('操作', 0.325898701227582),
 ('请求', 0.3150319289640483),
 ('分配', 0.3122916575249211),
 ('允许', 0.29138009075742605),
 ('基本', 0.28062153944119445),
 ('并发', 0.25286860151890117)]

3.4 词性标注

  • jieba.posseg.POSTokenizer(tokenizer=None) 新建自定义分词器,tokenizer 参数可指定内部使用的 jieba.Tokenizer 分词器;
  • jieba.posseg.dt (default) 为默认词性标注分词器;
  • 标注句子分词后每个词的词性,采用和 ictclas 兼容的标记法;
  • 除了 jieba 默认分词模式,提供 paddle 模式下的词性标注功能。paddle 模式采用延迟加载方式,通过 enable_paddle() 安装 paddlepaddle-tiny,并且 import 相关代码。
import jieba
import jieba.posseg as pseg

words = pseg.cut("我爱北京天安门")  # jieba 默认模式
jieba.enable_paddle()  # 启动 paddle 模式。 0.40版之后开始支持,早期版本不支持
words = pseg.cut("我爱北京天安门", use_paddle=True)  # paddle模式
for word, flag in words:
    print('%s %s' % (word, flag))

# 结果
Paddle enabled successfully......
我 r
爱 v
北京 LOC
天安门 LOC
words = pseg.cut("我爱北京天安门", use_paddle=False)  # paddle模式
for word, flag in words:
    print('%s %s' % (word, flag))

# 结果
我 r
爱 v
北京 ns
天安门 ns

3.5 并行分词

  • 原理:将目标文本按行分隔后,把各行文本分配到多个 Python 进程并行分词,然后归并结果,从而获得分词速度的可观提升

  • 基于 python 自带的 multiprocessing 模块,目前暂不支持 Windows

  • 用法:

    • jieba.enable_parallel(4) # 开启并行分词模式,参数为并行进程数
    • jieba.disable_parallel() # 关闭并行分词模式
  • 例子:https://github.com/fxsjy/jieba/blob/master/test/parallel/test_file.py

  • 实验结果:在 4 核 3.4GHz Linux 机器上,对金庸全集进行精确分词,获得了 1MB/s 的速度,是单进程版的 3.3 倍。

  • 注意:并行分词仅支持默认分词器 jieba.dt 和 jieba.posseg.dt。

3.6 Tokenize:返回词语在原文的起止位置

  • 注意,输入参数只接受 unicode
  • 默认模式
result = jieba.tokenize(u'永和服装饰品有限公司')
for tk in result:
    print("word %s\t\t start: %d \t\t end:%d" % (tk[0], tk[1], tk[2]))

# 结果
word 永和		 start: 0 		 end:2
word 服装		 start: 2 		 end:4
word 饰品		 start: 4 		 end:6
word 有限公司		 start: 6 		 end:10
  • 搜索模式
result = jieba.tokenize(u'永和服装饰品有限公司', mode='search')
for tk in result:
    print("word %s\t\t start: %d \t\t end:%d" % (tk[0], tk[1], tk[2]))

# 结果
word 永和		 start: 0 		 end:2
word 服装		 start: 2 		 end:4
word 饰品		 start: 4 		 end:6
word 有限		 start: 6 		 end:8
word 公司		 start: 8 		 end:10
word 有限公司		 start: 6 		 end:10

资料来源

Github jieba 中文分词

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表