中文分词,即 Chinese Word Segmentation,即将一个汉字序列进行切分,得到一个个单独的词。表面上看,分词其实就是那么回事,但分词效果好不好对信息检索、实验结果还是有很大影响的,同时分词的背后其实是涉及各种各样的算法的。
中文分词与英文分词有很大的不同,对英文而言,一个单词就是一个词,而汉语是以字为基本的书写单位,词语之间没有明显的区分标记,需要人为切分。根据其特点,可以把分词算法分为四大类:
下面我们对这几种方法分别进行总结。
这种方法又叫作机械分词方法、基于字典的分词方法,它是按照一定的策略将待分析的汉字串与一个“充分大的”机器词典中的词条进行匹配。若在词典中找到某个字符串,则匹配成功。该方法有三个要素,即分词词典、文本扫描顺序和匹配原则。文本的扫描顺序有正向扫描、逆向扫描和双向扫描。匹配原则主要有最大匹配、最小匹配、逐词匹配和最佳匹配。
此种方法优点是简单,易于实现。但缺点有很多:匹配速度慢;存在交集型和组合型歧义切分问题;词本身没有一个标准的定义,没有统一标准的词集;不同词典产生的歧义也不同;缺乏自学习的智能性。
该方法的主要思想:词是稳定的组合,因此在上下文中,相邻的字同时出现的次数越多,就越有可能构成一个词。因此字与字相邻出现的概率或频率能较好地反映成词的可信度。可以对训练文本中相邻出现的各个字的组合的频度进行统计,计算它们之间的互现信息。互现信息体现了汉字之间结合关系的紧密程度。当紧密程 度高于某一个阈值时,便可以认为此字组可能构成了一个词。该方法又称为无字典分词。
该方法所应用的主要的统计模型有:N 元文法模型(N-gram)、隐马尔可夫模型(Hiden Markov Model,HMM)、最大熵模型(ME)、条件随机场模型(Conditional Random Fields,CRF)等。
在实际应用中此类分词算法一般是将其与基于词典的分词方法结合起来,既发挥匹配分词切分速度快、效率高的特点,又利用了无词典分词结合上下文识别生词、自动消除歧义的优点。
语义分词法引入了语义分析,对自然语言自身的语言信息进行更多的处理,如扩充转移网络法、知识分词语义分析法、邻接约束法、综合匹配法、后缀分词法、特征词库法、矩阵约束法、语法分析法等。
基于理解的分词方法是通过让计算机模拟人对句子的理解,达到识别词的效果。其基本思想就是在分词的同时进行句法、语义分析,利用句法信息和语义信息来处理歧义现象。它通常包括三个部分:分词子系统、句法语义子系统、总控部分。在总控部分的协调下,分词子系统可以获得有关词、句子等的句法和语义信息来对分词歧义进行判断,即它模拟了人对句子的理解过程。这种分词方法需要使用大量的语言知识和信息。目前基于理解的分词方法主要有专家系统分词法和神经网络分词法等。
以上便是对分词算法的基本介绍,接下来我们再介绍几个比较实用的分词 Python 库及它们的使用方法。
在这里介绍几个比较有代表性的支持分词的 Python 库,主要有:
专用于分词的 Python 库,GitHub:https://github.com/fxsjy/jieba,分词效果较好。
支持三种分词模式:
另外 jieba 支持繁体分词,支持自定义词典。
其使用的算法是基于统计的分词方法,主要有如下几种:
首先我们来看下精确模式分词,使用 lcut() 方法,类似 cut() 方法,其参数和 cut() 是一致的,只不过返回结果是列表而不是生成器,默认使用精确模式,代码如下:
import jieba
string = '这个把手该换了,我不喜欢日本和服,别把手放在我的肩膀上,工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作'
result = jieba.lcut(string)
print(len(result), '/'.join(result))
结果:
38 这个/把手/该换/了/,/我/不/喜欢/日本/和服/,/别/把手/放在/我/的/肩膀/上/,/工信处/女干事/每月/经过/下属/科室/都/要/亲口/交代/24/口/交换机/等/技术性/器件/的/安装/工作
可见分词效果还是不错的。
使用全模式分词需要添加 cut_all 参数,将其设置为 True,代码如下:
result = jieba.lcut(string, cut_all=True)
print(len(result), '/'.join(result))
结果如下:
51 这个/把手/该换/了///我/不/喜欢/日本/和服///别/把手/放在/我/的/肩膀/上///工信处/处女/女干事/干事/每月/月经/经过/下属/科室/都/要/亲口/口交/交代/24/口交/交换/交换机/换机/等/技术/技术性/性器/器件/的/安装/安装工/装工/工作
使用搜索引擎模式分词需要调用 cut_for_search() 方法,代码如下:
result = jieba.lcut_for_search(string)
print(len(result), '/'.join(result))
结果如下:
42 这个/把手/该换/了/,/我/不/喜欢/日本/和服/,/别/把手/放在/我/的/肩膀/上/,/工信处/干事/女干事/每月/经过/下属/科室/都/要/亲口/交代/24/口/交换/换机/交换机/等/技术/技术性/器件/的/安装/工作
另外可以加入自定义词典,如我们想把 日本和服 作为一个整体,可以把它添加到词典中,代码如下:
jieba.add_word('日本和服')
result = jieba.lcut(string)
print(len(result), '/'.join(result))
结果如下:
37 这个/把手/该换/了/,/我/不/喜欢/日本和服/,/别/把手/放在/我/的/肩膀/上/,/工信处/女干事/每月/经过/下属/科室/都/要/亲口/交代/24/口/交换机/等/技术性/器件/的/安装/工作
可以看到切分结果中,日本和服 四个字就作为一个整体出现在结果中了,分词数量比精确模式少了一个。
另外 jieba 还支持词性标注,可以输出分词后每个词的词性,实例如下:
words = pseg.lcut(string)
print(list(map(lambda x: list(x), words)))
运行结果:
[['这个', 'r'], ['把手', 'v'], ['该', 'r'], ['换', 'v'], ['了', 'ul'], [',', 'x'], ['我', 'r'], ['不', 'd'], ['喜欢', 'v'], ['日本和服', 'x'], [',', 'x'], ['别', 'r'], ['把手', 'v'], ['放在', 'v'], ['我', 'r'], ['的', 'uj'], ['肩膀', 'n'], ['上', 'f'], [',', 'x'], ['工信处', 'n'], ['女干事', 'n'], ['每月', 'r'], ['经过', 'p'], ['下属', 'v'], ['科室', 'n'], ['都', 'd'], ['要', 'v'], ['亲口', 'n'], ['交代', 'n'], ['24', 'm'], ['口', 'n'], ['交换机', 'n'], ['等', 'u'], ['技术性', 'n'], ['器件', 'n'], ['的', 'uj'], ['安装', 'v'], ['工作', 'vn']]
关于词性的说明可以参考:https://gist.github.com/luw2007/6016931。
SnowNLP: Simplified Chinese Text Processing,可以方便的处理中文文本内容,是受到了 TextBlob 的启发而写的,由于现在大部分的自然语言处理库基本都是针对英文的,于是写了一个方便处理中文的类库,并且和 TextBlob 不同的是,这里没有用 NLTK,所有的算法都是自己实现的,并且自带了一些训练好的字典。GitHub地址:https://github.com/isnowfy/snownlp。
这里的分词是基于 Character-Based Generative Model 来实现的,论文地址:http://aclweb.org/anthology//Y/Y09/Y09-2047.pdf,我们还是以上面的例子说明,相关使用说明如下:
from snownlp import SnowNLP
string = '这个把手该换了,我不喜欢日本和服,别把手放在我的肩膀上,工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作'
s = SnowNLP(string)
result = s.words
print(len(result), '/'.join(result))
运行结果:
40 这个/把手/该/换/了/,/我/不/喜欢/日本/和/服/,/别把手/放在/我/的/肩膀/上/,/工/信处女/干事/每月/经过/下属/科室/都/要/亲口/交代/24/口/交换机/等/技术性/器件/的/安装/工作
经过观察,可以发现分词效果其实不怎么理想,和服 被分开了,工信处 也被分开了,女干事 也被分开了。
另外 SnowNLP 还支持很多功能,例如词性标注(HMM)、情感分析、拼音转换(Trie树)、关键词和摘要生成(TextRank)。
我们简单看一个实例:
print('Tags:', list(s.tags))
print('Sentiments:', s.sentiments)
print('Pinyin:', s.pinyin)
运行结果:
Tags: [('这个', 'r'), ('把手', 'Ng'), ('该', 'r'), ('换', 'v'), ('了', 'y'), (',', 'w'), ('我', 'r'), ('不', 'd'), ('喜欢', 'v'), ('日本', 'ns'), ('和', 'c'), ('服', 'v'), (',', 'w'), ('别把手', 'ad'), ('放在', 'v'), ('我', 'r'), ('的', 'u'), ('肩膀', 'n'), ('上', 'f'), (',', 'w'), ('工', 'j'), ('信处女', 'j'), ('干事', 'n'), ('每月', 'r'), ('经过', 'p'), ('下属', 'v'), ('科室', 'n'), ('都', 'd'), ('要', 'v'), ('亲口', 'd'), ('交代', 'v'), ('24', 'm'), ('口', 'q'), ('交换机', 'n'), ('等', 'u'), ('技术性', 'n'), ('器件', 'n'), ('的', 'u'), ('安装', 'vn'), ('工作', 'vn')]
Sentiments: 0.015678817603646866
Pinyin: ['zhe', 'ge', 'ba', 'shou', 'gai', 'huan', 'liao', ',', 'wo', 'bu', 'xi', 'huan', 'ri', 'ben', 'he', 'fu', ',', 'bie', 'ba', 'shou', 'fang', 'zai', 'wo', 'de', 'jian', 'bang', 'shang', ',', 'gong', 'xin', 'chu', 'nv', 'gan', 'shi', 'mei', 'yue', 'jing', 'guo', 'xia', 'shu', 'ke', 'shi', 'dou', 'yao', 'qin', 'kou', 'jiao', 'dai', '24', 'kou', 'jiao', 'huan', 'ji', 'deng', 'ji', 'shu', 'xing', 'qi', 'jian', 'de', 'an', 'zhuang', 'gong', 'zuo']
3. THULAC
THULAC(THU Lexical Analyzer for Chinese)由清华大学自然语言处理与社会人文计算实验室研制推出的一套中文词法分析工具包,GitHub 链接:https://github.com/thunlp/THULAC-Python,具有中文分词和词性标注功能。THULAC具有如下几个特点:
我们用一个实例看一下分词效果:
import thulac
string = '这个把手该换了,我不喜欢日本和服,别把手放在我的肩膀上,工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作'
t = thulac.thulac()
result = t.cut(string)
print(result)
运行结果:
[['这个', 'r'], ['把手', 'n'], ['该', 'v'], ['换', 'v'], ['了', 'u'], [',', 'w'], ['我', 'r'], ['不', 'd'], ['喜欢', 'v'], ['日本', 'ns'], ['和服', 'n'], [',', 'w'], ['别把手', 'n'], ['放', 'v'], ['在', 'p'], ['我', 'r'], ['的', 'u'], ['肩膀', 'n'], ['上', 'f'], [',', 'w'], ['工信处', 'n'], ['女', 'a'], ['干事', 'n'], ['每月', 'r'], ['经过', 'p'], ['下属', 'v'], ['科室', 'n'], ['都', 'd'], ['要', 'v'], ['亲口', 'd'], ['交代', 'v'], ['24', 'm'], ['口', 'q'], ['交换机', 'n'], ['等', 'u'], ['技术性', 'n'], ['器件', 'n'], ['的', 'u'], ['安装', 'v'], ['工作', 'v']]
NLPIR 分词系统,前身为2000年发布的 ICTCLAS 词法分析系统,GitHub 链接:https://github.com/NLPIR-team/NLPIR,是由北京理工大学张华平博士研发的中文分词系统,经过十余年的不断完善,拥有丰富的功能和强大的性能。NLPIR是一整套对原始文本集进行处理和加工的软件,提供了中间件处理效果的可视化展示,也可以作为小规模数据的处理加工工具。主要功能包括:中文分词,词性标注,命名实体识别,用户词典、新词发现与关键词提取等功能。另外对于分词功能,它有 Python 实现的版本,GitHub 链接:https://github.com/tsroten/pynlpir。
使用方法如下:
import pynlpir
pynlpir.open()
string = '这个把手该换了,我不喜欢日本和服,别把手放在我的肩膀上,工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作'
result = pynlpir.segment(string)
print(result)
运行结果如下:
[('这个', 'pronoun'), ('把', 'preposition'), ('手', 'noun'), ('该', 'pronoun'), ('换', 'verb'), ('了', 'modal particle'), (',', 'punctuation mark'), ('我', 'pronoun'), ('不', 'adverb'), ('喜欢', 'verb'), ('日本', 'noun'), ('和', 'conjunction'), ('服', 'verb'), (',', 'punctuation mark'), ('别', 'adverb'), ('把', 'preposition'), ('手', 'noun'), ('放', 'verb'), ('在', 'preposition'), ('我', 'pronoun'), ('的', 'particle'), ('肩膀', 'noun'), ('上', 'noun of locality'), (',', 'punctuation mark'), ('工', 'noun'), ('信', 'noun'), ('处女', 'noun'), ('干事', 'noun'), ('每月', 'pronoun'), ('经过', 'preposition'), ('下属', 'verb'), ('科室', 'noun'), ('都', 'adverb'), ('要', 'verb'), ('亲口', 'adverb'), ('交代', 'verb'), ('24', 'numeral'), ('口', 'classifier'), ('交换机', 'noun'), ('等', 'particle'), ('技术性', 'noun'), ('器件', 'noun'), ('的', 'particle'), ('安装', 'verb'), ('工作', 'verb')]
这里 把手 和 和服 也被分开了。
NLTK,Natural Language Toolkit,是一个自然语言处理的包工具,各种多种 NLP 处理相关功能,GitHub 链接:https://github.com/nltk/nltk。
但是 NLTK 对于中文分词是不支持的,示例如下:
from nltk import word_tokenize
string = '这个把手该换了,我不喜欢日本和服,别把手放在我的肩膀上,工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作'
result = word_tokenize(string)
print(result)
结果:
['这个把手该换了,我不喜欢日本和服,别把手放在我的肩膀上,工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作']
如果要用中文分词的话,可以使用 FoolNLTK,它使用 Bi-LSTM 训练而成,包含分词、词性标注、实体识别等功能,同时支持自定义词典,可以训练自己的模型,可以进行批量处理。
使用方法如下:
import fool
string = '这个把手该换了,我不喜欢日本和服,别把手放在我的肩膀上,工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作'
result = fool.cut(string)
print(result)
运行结果:
[['这个', '把手', '该', '换', '了', ',', '我', '不', '喜欢', '日本', '和服', ',', '别', '把', '手', '放', '在', '我', '的', '肩膀', '上', ',', '工信处', '女', '干事', '每月', '经过', '下属', '科室', '都', '要', '亲', '口', '交代', '24', '口', '交换机', '等', '技术性', '器件', '的', '安装', '工作']]
可以看到这个分词效果还是不错的。
另外还可以进行词性标注,实体识别:
result = fool.pos_cut(string)
print(result)
_, ners = fool.analysis(string)
print(ners)
运行结果:
[[('这个', 'r'), ('把手', 'n'), ('该', 'r'), ('换', 'v'), ('了', 'y'), (',', 'wd'), ('我', 'r'), ('不', 'd'), ('喜欢', 'vi'), ('日本', 'ns'), ('和服', 'n'), (',', 'wd'), ('别', 'd'), ('把', 'pba'), ('手', 'n'), ('放', 'v'), ('在', 'p'), ('我', 'r'), ('的', 'ude'), ('肩膀', 'n'), ('上', 'f'), (',', 'wd'), ('工信处', 'ns'), ('女', 'b'), ('干事', 'n'), ('每月', 'r'), ('经过', 'p'), ('下属', 'v'), ('科室', 'n'), ('都', 'd'), ('要', 'v'), ('亲', 'a'), ('口', 'n'), ('交代', 'v'), ('24', 'm'), ('口', 'q'), ('交换机', 'n'), ('等', 'udeng'), ('技术性', 'n'), ('器件', 'n'), ('的', 'ude'), ('安装', 'n'), ('工作', 'n')]]
[[(12, 15, 'location', '日本')]]
语言技术平台(Language Technology Platform,LTP)是哈工大社会计算与信息检索研究中心历时十年开发的一整套中文语言处理系统。LTP制定了基于XML的语言处理结果表示,并在此基础上提供了一整套自底向上的丰富而且高效的中文语言处理模块(包括词法、句法、语义等6项中文处理核心技术),以及基于动态链接库(Dynamic Link Library, DLL)的应用程序接口、可视化工具,并且能够以网络服务(Web Service)的形式进行使用。
LTP 有 Python 版本,GitHub地址:https://github.com/HIT-SCIR/pyltp,另外运行的时候需要下载模型,模型还比较大,下载地址:http://ltp.ai/download.html。
示例代码如下:
from pyltp import Segmentor
string = '这个把手该换了,我不喜欢日本和服,别把手放在我的肩膀上,工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作'
segmentor = Segmentor()
segmentor.load('./cws.model')
result = list(segmentor.segment(string))
segmentor.release()
print(result)
运行结果:
41 这个/把手/该/换/了/,/我/不/喜欢/日本/和服/,/别/把/手/放在/我/的/肩膀/上/,/工信/处女/干事/每月/经过/下属/科室/都/要/亲口/交代/24/口/交换机/等/技术性/器件/的/安装/工作
可以发现 工信处、女干事 没有正确分开。
以上便是一些分词库的基本使用,个人比较推荐的有 jieba、THULAC、FoolNLTK。
崔庆才
静觅博客博主,《Python3网络爬虫开发实战》作者