在逐渐步入DT(DataTechnology)时代的今天,自然语义分析技术越发不可或缺。对于我们每天打交道的中文来说,并没有类似英文空格的边界标志。而理解句子所包含的词语,则是理解汉语语句的第一步。汉语自动分词的任务,通俗地说,就是要由机器在文本中的词与词之间自动加上空格。
一提到自动分词,通常会遇到两种比较典型的质疑。一种质疑是来自外行人的:这件事看上去平凡之极,好像一点儿也不“fancy”,会有什么用呢?另一种质疑则是来自业内:自动分词研究已经进行了数年,而网上也存在各种不同的开放分词系统,但对于实际商用似乎也未见一个“即插即用”的系统。
那么,目前常见的开放分词引擎,到底性能如何呢?为了进行测试,我们调研了11款网上常见的并且公开提供服务的分词系统,包括:
分词的客观量化测试离不开标注数据,即人工所准备的分词“标准答案”。在数据源方面,我们将测试分为:
准确度计算规则:
以上所有数据采用北大现代汉语基本加工规范对所有数据进行分词作为标准。具体数据下载地址请参见附录。通过这四类数据综合对比不同分词系统的分词准确度。
上图为参与比较的10款分词引擎在不同数据的分词准确度结果。可以看出,在所测试的四个数据集上,BosonNLP和哈工大语言云都取得了较高的分词准确率,尤其在新闻数据上。因为庖丁解牛是将所有可能成词的词语全部扫描出来(例如:“最不满意”分为:“最不不满满意”),与其他系统输出规范不同,因而不参与准确率统计。为了更直接的比较不同数据源的差别,我们从每个数据源的测试数据中抽取比较典型的示例进行更直观的对比。
【新闻数据】新闻数据的特点是用词规整,符合语法规则,也是普遍做得比较不错的一个领域。对比其他数据源,有7家系统都在新闻领域达到最高。包括IKAnalyzer、盘古分词、搜狗分词、新浪云、NLPIR、语言云、BosonNLP。并且有三家系统准确率超过90%。
样例:香港中文大学将来合肥一中进行招生宣传今年在皖招8人万家热线安徽第一门户
【微博数据】微博数据用词多样、话题广泛,并常包含错别字及网络流行词。能够比较全面的体现每家分词系统的准确度。
样例:补了battle赛峰暴班的两个弟弟妹妹@杨宝心@修儿一个是我很挺的好弟弟一个是我推荐进好声音的妹子虽然都在battle阶段都下来了但是我依然像之前那样觉得你们非常棒
【汽车论坛】汽车数据是针对汽车领域的专业评价数据,会出现很多的专业术语。例如示例中的“胎噪”、“风燥”等,如果系统没有足够强大的训练词库或领域优化,会使准确率有较大程度降低。比较有意思的是,对比其他数据源,有3家系统都在汽车论坛领域达到最高:腾讯文智、SCWS中文分词、结巴分词。
样例:舒适性胎噪风噪偏大避震偏硬过坎弹跳明显
样例:跟闺蜜在西单逛街想吃寿司了在西单没搜到其他的日料店就来禾绿了我们俩都觉得没以前好了
各家系统对于多数简单规范的文本的分词已经达到很高的水平。但在仔细对比每一家中文分词后依旧发现切分歧义词和未登陆词(即未在训练数据中出现的词)仍然是影响分词准确度的两大“拦路虎”。1.切分歧义:根据测试数据的切分结果,一类属于机器形式的歧义,在真实语言环境下,只有唯一可能的正确切分结果,称其为伪歧义。另一类有两种以上可实现的切分结果,称为真歧义。由于真歧义数据无法比较正确或者错误。所有我们着重举例来比较各家系统对伪歧义的处理效果。
正确:在伦敦奥运会上将可能有一位沙特阿拉伯的女子
(BosonNLP、新浪云、语言云、NLPIR、腾讯文智)
错误:在伦敦奥运会上将可能有一位沙特阿拉伯的女子
(PHP结巴分词、SCWS中文分词、搜狗分词、庖丁解牛)
a)新涌现的通用词:类似“神马”、“纳尼”、“甩卖”、“玫瑰金”等新思想、新事物所带来的新词汇,不管是文化的、政治的、还是经济的,在人们的生活中不断涌现。同时很多词语也具有一定的时效性。
c)专有名词:如中国人名、外国译名、地名、公司名等。这种词语很多基本上不可通过词典覆盖,考验分词系统的新词识别能力。
【新涌现的通用词或专业术语】示例中的蓝色字包括专业术语:“肚腩”、“腹肌”、“腹直肌”、“腹外斜肌”、“腹横肌”;新涌现的通用词:“人鱼线”、“马甲线”。大多数的系统对于示例文本的分词结果都不够理想,例如:“大肚腩”(SCWS中文分词)“腹直肌腹外斜肌”(搜狗分词、IKAnalyer、NLPIR、SCWS中文分词)、“人鱼线”(PHP结巴分词)。总的来说这两种类型的数据每家系统都存在一定的缺陷,相对而言哈工大的语言云在这方面表现的较好。
本季最强家庭瘦腰计划彻底告别大肚腩没有腹肌的人生是不完整的平面模特yanontheway亲身示范的9个动作彻底强化腹直肌腹外斜肌腹内斜肌以及腹横肌每个动作认真做足50次一定要坚持做完美的人鱼线性感的马甲线都要我们自己去争取
【专有名词】示例出现的专有名词包括“蒂莫西伊斯顿”(姓名)、“英国”“意大利”“北欧”(地点)、“金斯敦”(机构名)、“伊丽莎白格林希尔兹”(机构名)。而这种用词典无法穷尽的专有名词也成为各家分词准确率降低的重要原因。其中搜狗分词、IKAnalyer、PHP结巴分词、腾讯文智、SCWS中文分词在新词识别时较为谨慎,常将这类专有名词切分成多个词语。
油画英国画家蒂莫西伊斯顿唯美风油画timothyeaston毕业于英国金斯敦艺术学院曾获伊丽莎白格林希尔兹基金会奖得以前往意大利和北欧学习一年的机会
当然在分词准确度可以接受的情况下,很多细节问题,包括是否有出错情况、是否支持各种字符、是否标注词性等都可能让我们望而却步。在分词颗粒度选择当中,BosonNLP、SCWS、盘古分词、结巴分词、庖丁解牛都提供了多种选择,可以根据需求来采用不同的分词粒度。与北大的分词标准对比来说,新浪云默认的分词粒度较大,而搜狗分词、腾讯文智分词粒度相对较小。除此之外,BosonNLP、新浪云、NLPIR、腾讯文智同时提供了实体识别、情感分析、新闻分类等其他扩展服务。下表给出了各家系统在应用方面的详细对比。
中文分词是其他中文信息处理的基础,并且在很多领域都有广泛的应用,包括搜索引擎、机器翻译(MT)、语音合成、自动分类、自动摘要、自动校对等等。随着非结构化文本的广泛应用,中文分词等文本处理技术也变得越来越重要。通过评测可以看出,部分开放分词系统在不同领域已经达到较高准确率。对于数据分析处理的从业者,相信在此之上构建数据分析系统、人机交互平台,更能够起到事半功倍的效果。
注意:分词数据准备及评测由BosonNLP完成。
附录
评测数据地址
各家分词系统链接地址
腾讯文智:
本文的内容为以下两个部分:文本分词(jieba)语料库制作(gensim)结巴(jieba)分词在自然语言处理领域中,分词和提取关键词都是对文本处理时通常要进行的步骤。用Python语言对英文文本进行预处理时可选择NLTK库,中文文本预处理可选择jieba库。结巴分词是基于统计的分词方法,它对给出大量已经分词的文本,利用统计机器学习模型学习词语切分的规律(称为训练),从而实现对未知文本的切分。例如最大概率分词方法和最大熵分词方法等。随着大规模语料库的建立,统计机器学习方法的研究和发展,基于统计的中文分词方法渐渐成为了主流方法。
jieba分词的三种模式:精确模式:将句子最精确的分开,适合文本分析全模式:句子中所有可以成词的词语都扫描出来,速度快,不能解决歧义搜索引擎模式:在精确的基础上,对长词再次切分,提高召回结巴分词的其他特点诸如:支持繁体分词,支持自定义词典,基于Trie树结构实现高效的词图扫描,采用了动态规划查找最大概率路径等特点。
jieba库中分词函数
1、jieba.cut()方法参数string:需要接受分词的字符串。参数cut_all:控制是否采用全模式分词发,参数为True时表示采用全模式。参数HMM:控制是否使用HMM模型,参数为True时表示使用HMM模型。
2、jieba.cut_for_search()参数string:需要接受分词的字符串。参数HMM:控制是否使用HMM模型,参数为True时表示使用HMM模型。
jieba.cut以及jieba.cut_for_search返回的结构都是一个可迭代的generator,可以使用for循环来获得分词后得到的每一个词语。jieba.lcut和jieba.lcut_for_search参数和上面两个方法一致但返回的是一个list。
importjiebastring='上海市浦东新区世纪大道100号楼501'#精准模式text_cut=jieba.cut(string)print("".join(text_cut))#全模式text_cut=jieba.cut(string,cut_all=True)print("".join(text_cut))#搜索模式text_cut=jieba.cut_for_search(string)print("".join(text_cut))三种模式的输出结果:
精准模式:上海市浦东新区世纪大道100号楼501
全模式:上海上海市上海市浦东新区海市浦东浦东新区新区世纪纪大大道100号楼501
搜索引擎模式:上海海市浦东新区上海市上海市浦东新区世纪大道100号楼501
jieba分词自定义字典在使用jieba时,用户除了直接对文本进行分词外,还可以自行添加新词,已达到优化分词效果的目的。
1、加载自定义字典jieba.load_userdict()参数filename:为文件类对象或自定义词典的路径词典格式分为3个部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒。file_name若为路径或二进制方式打开的文件,则文件必须为UTF-8编码。
2、从字典中添加或删除词汇add_word、del_wordadd_word(word,freq=None,tag=None),add_word有3个参数,添加词名称,词频,词性del_word(word),del_word只有一个参数词语名称
3、词频调整suggest_freqsuggest_freq(segment,tune=True)调节单个词语的词频,可以使其能(或不能)被分出来,词频越高在分词时,能够被分出来的概率越大。
importjieba#载入自定义词典jieba.load_userdict('word_dict.txt')#查看用户自定义词典中的内容print(jieba.user_word_tag_tab)#往自定义词典中添加新词jieba.add_word('人民广场',freq=5,tag='n')#添加新词后的结果print(jieba.user_word_tag_tab)string='上海市浦东新区世纪大道100号楼501'text_cut=jieba.cut(string)print("".join(text_cut))#调整词频,重新分词jieba.suggest_freq(('上海市','浦东新区'),tune=True)text_cut=jieba.cut(string)print("".join(text_cut))输出结果:
载入词典内容:{'世纪大道':'n','浦东新区2':'n','世纪公园3':'n'}
添加新词后:{'世纪大道':'n','浦东新区2':'n','世纪公园3':'n','人民广场':'n'}
结巴原始字典库,分词结果:上海市浦东新区世纪大道100号楼501
使用自定义词典后,分词结果:上海市浦东新区世纪大道100号楼501
调整词频后,分词结果:上海市浦东新区世纪大道100号楼501
GensimGensim是一款开源的第三方Python工具包,用于从原始的非结构化的文本中,无监督地学习到文本隐层的主题向量表达。它支持包括TF-IDF,LSA,LDA,和word2vec在内的多种主题模型算法。
语料(Corpus):一组原始文本的集合,用于无监督地训练文本主题的隐层结构。在Gensim中,Corpus通常是一个可迭代的对象(比如列表)。每一次迭代返回一个可用于表达文本对象的稀疏向量。向量(Vector):由一组文本特征构成的列表。是一段文本在Gensim中的内部表达。在向量空间模型中,每个文档被表示成了一组特征,比如,一个单一的特征可能被视为一个问答对。稀疏向量(SparseVector):通常,大部分问题的答案都是0,为了节约空间,我们会从文档表示中省略他们,向量中的每一个元素是一个(key,value)的元组,比如(1,3),(2,4),(5,0),其中(5,0)是一个稀疏向量,在表示是会被忽略。模型(Model):是一个抽象的术语。定义了两个向量空间的变换(即从文本的一种向量表达变换为另一种向量表达)。把几个概念组织起来表述:gensim可以通过读取一段语料,输出一个向量,表示文档中的一个词。为了节约空间,通常稀疏的词向量会被忽略,剩下的词向量则可以用来训练各种模型,即从原有的文本表达转向另一种文本表达。
语料库制作
语料库制作主要包含两个过程:获取词袋:本文主要来自于结巴分词结果向量转换:对获取的词袋进行向量转换
importjiebaimportgensimprint(jieba.user_word_tag_tab)string=['上海市浦东新区世纪大道100号楼501','上海市世纪大道100号楼501']texts_list=[]forsentenceinstring:sentence_list=[wordforwordinjieba.cut(sentence)]texts_list.append(sentence_list)dictionary=gensim.corpora.Dictionary(texts_list)print(dictionary)print(dictionary.token2id)输出结果:Dictionary(7uniquetokens:['100','501','上海市浦东新区','世纪','号楼']...){'100':0,'501':1,'上海市浦东新区':2,'世纪':3,'号楼':4,'大道':5,'上海市':6}
第一行结果告诉我们语料库中有7个不同的单词,这表明每个文档将会用7个数字表示(即7维向量)。第二行结果是查看单词与编号之间的映射关系。
2、向量转换dictionary.doc2bow()
函数doc2bow()简单地对每个不同单词的出现次数进行了计数,并将单词转换为其编号,然后以稀疏向量的形式返回结果。
corpus=[dictionary.doc2bow(doc)fordocintexts_list]print(corpus)输出结果:[[(0,1),(1,1),(2,1),(3,1),(4,1),(5,1)],[(0,1),(1,1),(3,1),(4,1),(5,1),(6,1)]]
以上结果中,表示两个字符串中,每个词的id以及它对应的出现频次,比如第一个元组(0,1)代表的是编号为0的词在第一个字符串中出现一次。