一个中文文本从形式上看是由汉字(包括标点符号等)组成的一个字符串。由字可组成词,由词可组成句子,进而由一些句子组成段、节、章、篇。可见,如果需要处理一篇中文语料,从中正确的识别出词是一件非常基础而重要的工作。
1、中文分词概述
显而易见,中文以字为基本书写单位,词语之间没有明显的区分标记。中文分词就是由机器在词与词之间加上标记进行区分。例如:
输入: 我是学生。
输出: 我/是/学生/。
1.1 中文分词的关键问题
中文分词的关键问题为:切分歧义消解和未登录词识别
1.2 歧义切分定义
歧义切分的表示可以由下示例:
输入待切分句子:提高人民生活水平
可以切分输出 :提高/人民/生活/水平
或者切分输出:提/高人/民生/活水/平
明显第二个输出为歧义切分
1.3未登录词定义
常见的未登录词有实体名词、专有名词与新词
实体名词包括有:
中国人名:李素丽 老张 李四 王二麻子
中国地名:定福庄 白沟 三义庙 韩村 河马甸
翻译人名:乔治•布什 叶利钦 包法利夫人 酒井法子
翻译地名:阿尔卑斯山 新奥尔良 约克郡
机构名 :方正公司 联想集团 国际卫生组织 外贸部
商标字号:非常可乐 乐凯 波导 杉杉 同仁堂
专业术语和新词语
专业术语:万维网 主机板 模态 逻辑 贝叶斯算法
缩略语 :三个代表 五讲四美 打假 扫黄打非 计生办
新词语 :卡拉OK 波波族 美刀 港刀
未登录词没有明确边界,缺少英语中的分隔符、大小写、词的形态、冠词等语法信息,识别比较困难。
因此通常每一类未登录词都要构造专门的识别算法。
2、分词主要技术方法
2.1 基于词典的分词
词典中一般存储着:词、词频、词性等信息,可以通过统计标注好的熟语料和常用词典得到。
基于词典分词方法首先需要对句子进行原子切分,即找出句子中可能蕴含组成的所有词,然后构成词图。还是之前例子,输入:
提高人民生活水平
输出所有包括的词:
提 —提高
高 —高人
人 —人民
民 —民生
生—生活
活—活水
水 —水平
平
则可以构成词图如下:
词图.jpg上述工作主要重点是词典存储于并快速匹配,多采用双数组Tie树的方法生成词典树,用自动机匹配词串。
2.2词典分词的歧义消解问题
歧义消解可以转换为对于上述在词图上寻找统计意义上的最佳路径。常用一元、二元模型进行。
基于一元模型进行评价:
统计词表中每个词的词频,并将其转化为路径代价C=-log(f/N)切分路径的代价为路径上所有词的代价之和寻求代价最小的路径。上述例子就是根据词典中<提高><高人><人民><民生><生活><活水><水平><平>这几个词的词频f,认为词频越高的路径代价越小,找出最短的路径。
基于二元模型进行评价:
相对于一元模型,二元模型还需要一个词转移统计词典,例如记录了<提高>衔接<人民>的次数,词转移统计词典实质上是一个稀疏矩阵。基于二元模型进行评价需要在一元模型的基础上增加转移路径代价。词典中转移次数多的衔接认为该衔接转移路径代价小。计算方法可以用Viterbi算法。
2.3词典分词的未登陆词问题
简单来说,可以将未登陆词的识别转换成序列标注问题即打标签,然后用HMM或其它统计学习方法求解。例如中国人名识别可以表示为(姓+名)的形式,例如对于一个人名:金三胖 可以正确标注序列为:金/姓 三胖/名,则人名可以识别出来。具体可参见张华平相关论文《基于层叠隐马尔可夫模型的中文命名实体识别》、《基于角色标注的中国人名自动识别研究》、《基于角色标注的中文机构名识别》。
2.4基于字的分词
基于字的分词可以平衡的看待词表词和未登录词的识别问题。
汉语中词都是有字组成的,可以将分词视为字的序列标注问题。例如对于“占”这个字可以有以下词位标注:
-
词首B 占领
-
词尾E 抢占
-
词中M 独占鳌头
-
单字词S 已占全国
基于字的分词实现很简单,例如对于句子
上海/计划/到/本/世纪/末/实现/人均/国内/生产/总值/五千美元/。
可以有如下词位序列标注:
上/B海/E计/B划/E到/S本/S世/B纪/E末/S实/B现/E人/B均/E国/B内/E生/B产/E总/B值/E五/B千/M美/M元/E。/S
根据标注BMES实现了分词。
转换成序列标注问题后常用算法有HMM (隐马模型)、MEMM(最大熵隐马模型)、CRF等。下面简单比较一下:
隐马模型一个最大的缺点就是由于其输出独立性假设,导致其不能考虑上下文的特征,限制了特征的选择。
最大熵隐马模型则解决了隐马的问题,可以任意选择特征,但由于其在每一节点都要进行归一化,所以只能找到局部的最优值,同时也带来了标记偏见的问题,即凡是训练语料中未出现的情况全都忽略掉。
条件随机场则很好的解决了这一问题,他并不在每一个节点进行归一化,而是所有特征进行全局归一化,因此可以求得全局的最优值。
2.5 主要分词技术评价
- 基于词典的分词优点:
速度快,效率高,易修改,灵活性强。
- 基于词典的分词缺点:
主要依赖词典和规则库,对于歧义词和未登录词的识别能力较低。
- 基于字的分词的优点:
对于歧义词和未登录词的识别能力较好。
- 基于字的分词的缺点:
(1)模型体积大占内存。例如一个可供生产环境用的CRF模型至少使用前中后3个字符的组合做特征模板,在一两百兆的语料上训练,模型体积至少上百兆。
(2)速度慢。相较于基于词语的BiGram分词器,一个拖速度的地方是特征函数的查询次数多、速度慢,另一个弱点则是概率图的节点更多(4倍文本长度个节点,4是BMES标签的个数)。
(3)不易修改。有时候用户对分词结果不满意,却无法方便地修正它。包括CRF在内的其他模型都需要重新训练,或者修改代码。而基于词语的NGram词典和词频词典可以轻松修改。
在自然语言处理过程中,为了能更好地处理句子,往往需要把句子拆开分成一个一个的词语,这样能更好的分析句子的特性,这个过程叫做——分词.
Github上已经有造好的轮子了,用别人的吧,而且,假如自己造的轮子在短时间内也没有别人的好用,废话少说,我们看看jieba中文分词。
结巴分词支持三种分词模式:
-
精确模式,试图将句子最精确地切开,适合文本分析;
-
全模式,把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义;
-
搜索引擎模式,在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。
算法:
-
基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图 (DAG)
-
采用了动态规划查找最大概率路径, 找出基于词频的最大切分组合
-
对于未登录词,采用了基于汉字成词能力的 HMM 模型,使用了 Viterbi 算法
(这应该是分词的原理,以后挑个好日子,坐下来,好好地去梳理下)
主要方法:
-
jieba.cut 方法接受三个输入参数: 需要分词的字符串;cut_all 参数用来控制是否采用全模式;HMM 参数用来控制是否使用 HMM 模型
-
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 为默认分词器,所有全局分词相关函数都是该分词器的映射。例如:
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))
输出:
Building prefix dict from the default dictionary ...
Dumping model to file cache C:\Users\lenovo\AppData\Local\Temp\jieba.cache
Loading model cost 5.787 seconds.
Prefix dict has been built succesfully.
Full Mode: 我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学
Default Mode: 我/ 来到/ 北京/ 清华大学
他, 来到, 了, 网易, 杭研, 大厦
小明, 硕士, 毕业, 于, 中国, 科学, 学院, 科学院, 中国科学院, 计算, 计算所, ,, 后, 在, 日本, 京都, 大学, 日本京都大学, 深造
添加自定义词典(如果觉得jieba自己的词典不够,你还可以自己添加)。
-
开发者可以指定自己自定义的词典,以便包含 jieba 词库里没有的词。虽然 jieba 有新词识别能力,但是自行添加新词可以保证更高的正确率
-
用法: jieba.load_userdict(file_name) # file_name 为文件类对象或自定义词典的路径
-
词典格式和 dict.txt 一样,一个词占一行;每一行分三部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒。file_name 若为路径或二进制方式打开的文件,则文件必须为 UTF-8 编码。
-
词频省略时使用自动计算的能保证分出该词的词频。
调整词典
-
使用 add_word(word, freq=None, tag=None) 和 del_word(word) 可在程序中动态修改词典。
-
使用 suggest_freq(segment, tune=True) 可调节单个词语的词频,使其能(或不能)被分出来。
-
注意:自动计算的词频在使用 HMM 新词发现功能时可能无效。
关键词提取
-
基于 TF-IDF 算法的关键词抽取。
-
基于 TextRank 算法的关键词抽取。
词性标注
-
jieba.posseg.POSTokenizer(tokenizer=None) 新建自定义分词器,tokenizer 参数可指定内部使用的 jieba.Tokenizer 分词器。jieba.posseg.dt 为默认词性标注分词器。
-
标注句子分词后每个词的词性,采用和 ictclas 兼容的标记法。
并行分词
-
原理:将目标文本按行分隔后,把各行文本分配到多个 Python 进程并行分词,然后归并结果,从而获得分词速度的可观提升
-
基于 python 自带的 multiprocessing 模块,目前暂不支持 Windows。
Tokenize
- 返回词语在原文的起止位置
当然,你要是还想更加深入的了解,推荐《NLP汉语自然语言处理》
书籍简介
这本书是一本研究汉语自然语言处理方面的基础性,综合性书籍,涉及NLP的语言理论,算法和工程的方方面面,内容复杂。
本书包括NLP的语言理论部分,算法部分,案例部分,涉及汉语的发展历史,传统的句法理论,认知语言理论。需要指出的是系统的介绍认知语言学和算法设计相结合的中文NLP书籍,并从认识语言学的视角重新认识和分析了NLP的句法和语义相结合的数据结构。
分词
中文NLP比外文要难,难再第一步就是要将文本进行切词。我们知道中文常用字也就3500左右,但是单字往往意义不多,对理解句子的意思帮助不大。而且中文词之间没有空格等标识符,这增加了NLP的难度。
NLP第一步,就是从分词开始,目前市面上有ICTCLASS,jieba,HanNLP等,了解其分词算法原理,对更好的学习编程,使用编程语言处理文本数据有好处。
既然,我们掌握了基本的分词技术,那就来制作一个词云吧
用到的工具
-
原始数据:txt格式,可以用爬虫爬点网页数据做原始数据。为简单就先用txt练手好了。
-
提取关键词:jieba分词、停用词表
-
在线词云生成工具:TAGUL
简单分析一下
生成词云最关键的问题是中文分词,统计分析各个词的权重(权重较高的字体显示较大)。这些问题jieba分词已经帮我们解决了。我们只需要
import jieba.analyse
使用
jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())
方法即可,当然只是提取关键词还是不够的,因为有些没有意义的常用词诸如“我的”、“或者”、“一个”等词,会出现在结果里面,还需要一个“停用词表”来帮我们过滤结果。
我们的目标是提取关键词,并得到“关键词+制表符+权重”的文本,这里关键词和权重用制表符隔开是为了在用在线工具的时候,能顺利导入权重的值,决定词的大小(size)。
步骤:
-
安装jieba
pip install jieba
-
准备好txt文件和停用词表(网上可以下载到,txt格式即可)
-
编写代码
代码
import jieba.analyse
path = '你的txt文件路径'
file_in = open(path, 'r',encoding='utf-8',errors='ignore')
content = file_in.read()
try:
jieba.analyse.set_stop_words('你的停用词表路径')
tags = jieba.analyse.extract_tags(content, topK=100, withWeight=True)
for v, n in tags:
#权重是小数,为了凑整,乘了一万
print( v + '\t' + str(int(n * 10000)))
finally:
file_in.close()
打开TAGUL,开始制作词云,把结果贴进import words里
TAGUL的教程https://www.zhihu.com/question/35976761/answer/67023767?from=profile_answer_card
网友评论