全栈 - 17 NLP 使用jieba分词处理文本
这是全栈数据工程师养成攻略系列教程的第十七期:17 NLP 使用jieba分词处理文本。
我们对NLP是什么和做什么,以及和NLP领域相关的内容和应用有了一个大致的概览,现在让我们通过Python中的jieba中文分词
来进行部分实现。
jieba中文分词
中文分词是中文NLP的第一步,一个优秀的分词系统取决于足够的语料和完善的模型,很多机构和公司也都会开发和维护自己的分词系统。这里推荐的是一款完全开源、简单易用的分词工具,jieba中文分词
。官网在这里,https://github.com/fxsjy/jieba,里面提供了详细的说明文档。虽然jieba分词的性能并不是最优秀的,但它开源免费、使用简单、功能丰富,并且支持多种编程语言实现。
以下我们使用Python中的jieba分词完成一些基础NLP任务,如果对jieba分词感兴趣,希望了解更多内容,可以参考官方使用文档。首先没有jieba分词的话需要安装,使用pip即可。
pip install jieba
中文分词
中文分词的模型实现主要分类两大类:基于规则和基于统计。
基于规则是指根据一个已有的词典,采用前向最大匹配、后向最大匹配、双向最大匹配等人工设定的规则来进行分词。例如对于“上海自来水来自海上”这句话,使用前向最大匹配,即从前向后扫描,使分出来的词存在于词典中并且尽可能长,则可以得到“上海/自来水/来自/海上”。这类方法思想简单且易于实现,对数据量的要求也不高。当然,分词所使用的规则可以设计得更复杂,从而使分词效果更理想。但是由于中文博大精深、语法千变万化,很难设计足够全面而通用的规则,并且具体的上下文语境、词语之间的搭配组合也都会影响到最终的分词结果,这些挑战都使得基于规则的分词模型愈发力不从心。
基于统计是从大量人工标注语料中总结词的概率分布以及词之间的常用搭配,使用有监督学习训练分词模型。对于“上海自来水来自海上”这句话,一个最简单的统计分词想法是,尝试所有可能的分词方案,因为任何两个字之间,要么需要切分,要么无需切分。对于全部可能的分词方案,根据语料统计每种方案出现的概率,然后保留概率最大的一种。很显然,“上海/自来水/来自/海上”的出现概率比“上海自/来水/来自/海上”更高,因为“上海”和“自来水”在标注语料中出现的次数比“上海自”和“来水”更多。
其他常用的基于统计的分词模型还有HMM(Hidden Markov Model)和CRF(Conditional Random Field)等,以及将中文分词视为序列标注问题(BEMS,即将每个字标注成Begin、End、Middle、Single中的一个,输入字序列,输出标签序列),进而使用有监督学习、深度神经网络等模型进行中文分词。
jieba分词结合了基于规则和基于统计两类方法。首先基于前缀词典进行词图扫描,前缀词典是指词典中的词按照前缀包含的顺序排列,例如词典中出现了“上”,之后以“上”开头的词都会出现在这一块,例如“上海”,进而会出现“上海市”,从而形成一种层级包含结构。如果将词看作节点,词和词之间的分词符看作边,那么一种分词方案则对应着从第一个字到最后一个字的一条分词路径。因此,基于前缀词典可以快速构建包含全部可能分词结果的有向无环图,这个图中包含多条分词路径,有向是指全部的路径都始于第一个字、止于最后一个字,无环是指节点之间不构成闭环。基于标注语料,使用动态规划的方法可以找出最大概率路径,并将其作为最终的分词结果。
jieba提供了三种分词模式:
- 精确模式:试图将句子最精确地切开,适合文本分析;
- 全模式:把句子中所有可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义;
- 搜索引擎模式:在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。
以下代码使用jieba实现中文分词,使用jieba.cut()
函数并传入待分词的文本字符串即可,使用cut_all
参数控制选择使用全模式还是精确模式,默认为精确模式。如果需要使用搜索引擎模式,使用jieba.cut_for_search()
函数即可。运行以下代码之后,jieba首先会加载自带的前缀词典,然后完成相应的分词任务。
import jieba
seg_list = jieba.cut("我来到北京清华大学", cut_all=True)
# join是split的逆操作
# 即使用一个拼接符将一个列表拼成字符串
print("/ ".join(seg_list)) # 全模式
seg_list = jieba.cut("我来到北京清华大学", cut_all=False)
print("/ ".join(seg_list)) # 精确模式
seg_list = jieba.cut("他来到了网易杭研大厦") # 默认是精确模式
print("/ ".join(seg_list))
seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所,后在日本京都大学深造") # 搜索引擎模式
print("/ ".join(seg_list))
关键词提取
jieba实现了TF-IDF
和TextRank
这两种关键词提取算法,直接调用即可。当然,提取关键词的前提是中文分词,所以这里也会使用到jieba自带的前缀词典和IDF权重词典。
import jieba.analyse
# 字符串前面加u表示使用unicode编码
content = u'中国特色社会主义是我们党领导的伟大事业,全面推进党的建设新的伟大工程,是这一伟大事业取得胜利的关键所在。党坚强有力,事业才能兴旺发达,国家才能繁荣稳定,人民才能幸福安康。党的十八大以来,我们党坚持党要管党、从严治党,凝心聚力、直击积弊、扶正祛邪,党的建设开创新局面,党风政风呈现新气象。习近平总书记围绕从严管党治党提出一系列新的重要思想,为全面推进党的建设新的伟大工程进一步指明了方向。'
# 第一个参数:待提取关键词的文本
# 第二个参数:返回关键词的数量,重要性从高到低排序
# 第三个参数:是否同时返回每个关键词的权重
# 第四个参数:词性过滤,为空表示不过滤,若提供则仅返回符合词性要求的关键词
keywords = jieba.analyse.extract_tags(content, topK=20, withWeight=True, allowPOS=())
# 访问提取结果
for item in keywords:
# 分别为关键词和相应的权重
print item[0], item[1]
# 同样是四个参数,但allowPOS默认为('ns', 'n', 'vn', 'v')
# 即仅提取地名、名词、动名词、动词
keywords = jieba.analyse.textrank(content, topK=20, withWeight=True, allowPOS=('ns', 'n', 'vn', 'v'))
# 访问提取结果
for item in keywords:
# 分别为关键词和相应的权重
print item[0], item[1]
对于所提取的关键词以及权重,将每个关键词的权重作为文字大小,便可以进行字符云可视化。
词性标注
jieba在进行中文分词的同时,还可以完成词性标注任务。根据分词结果中每个词的词性,可以初步实现命名实体识别,即将标注为nr
的词视为人名,将标注为ns
的词视为地名等。所有标点符号都会被标注为x
,所以可以根据这个去除分词结果中的标点符号。
# 加载jieba.posseg并取个别名,方便调用
import jieba.posseg as pseg
words = pseg.cut("我爱北京天安门")
for word, flag in words:
# 格式化模版并传入参数
print('%s, %s' % (word, flag))
视频链接:使用jieba分词处理文本