分词工具哪家强?文本分析的利器
By 青衣极客 Blue Geek In 2019-12-13
最近有一个粗略的文本分析任务需要利用到文本分词工具,由于并没有NLP(自然语言处理)相关背景,就只能在互联网上调研一番。目前能够找到的公开工具有六七款之多,但是其中一些安装起来非常麻烦,或者所依赖的软硬件并不具有普遍适用性。经过逐个尝试之后,发现有四款工具安装和使用都相对比较简单。本文就简单评测一下这四款工具在个别实例上的分词效果以及其运行耗时, 分别是:jieba、SnowNLP、thulac和pyltp。
1. jieba模块
jieba这个工具的名字确实不太好听,特别是说出这个名字时很像在叫某些人绰号而显得不太正式。正所谓人不可貌相,海不可斗量,用软件也不能完全看名字。事实上,jieba是一款大名鼎鼎的分词工具,在很多的讨论交流社区都有很不错的口碑。这是一款python的第三方库,因此需要使用pip3 install jieba安装一下。这里使用《红楼梦》中的《好了歌》作为测试的输入文本,看看jieba模块会有什么效果。
text_haole = u'''世人都晓神仙好,惟有功名忘不了!古今将相在何方?荒冢一堆草没了。
世人都晓神仙好只有金银忘不了!终朝只恨聚无多,及到多时眼闭了。
世人都晓神仙好,只有姣妻忘不了!君生日日说恩情,君死又随人去了。
世人都晓神仙好,只有儿孙忘不了!痴心父母古来多,孝顺儿孙谁见了?'''
import jieba
words = jieba.cut(text_haole)
print(','.join(words))
Building prefix dict from the default dictionary ...
Loading model from cache /var/folders/st/45xslkfn7yx2_px9yl45z1080000gn/T/jieba.cache
Loading model cost 0.777 seconds.
Prefix dict has been built succesfully.
世人,都,晓,神仙,好,,,惟有,功名,忘不了,!,古今,将相,在,何方,?,荒冢,一堆,草,没,了,。,
,世人,都,晓,神仙,好,只有,金银,忘不了,!,终朝,只恨,聚无多,,,及,到,多时,眼闭,了,。,
,世人,都,晓,神仙,好,,,只有,姣妻,忘不了,!,君,生日,日,说,恩情,,,君死,又,随人,去,了,。,
,世人,都,晓,神仙,好,,,只有,儿孙,忘不了,!,痴心,父母,古来,多,,,孝顺,儿孙,谁,见,了,?
从代码上看,使用方式非常简单;从结果来看,在第一次使用时会载入默认的词典,该过程可能稍费时间,分词结果大体符合预期,基本能够保持一些词的组成。下面我们使用《乌合之众:大众心理学》的中文翻译来进行运行速度的测试。
import time
import re
# 提取中文文本
pattern = re.compile(r"[\u4e00-\u9fa5]")
with open('../data/the-crowd-a-study-of-the-popular-mind.txt', 'r') as fid:
text = fid.read().strip('\n').strip('\\n')
text_list = pattern.findall(text)
text_crowd = ''.join(text_list)
# 测试运行时间
start_time = time.time()
words = jieba.cut(text_crowd)
print('cost time {:.3f} secs'.format(time.time()-start_time))
# 打印部分分词结果
words = list(words)
print(words[:30])
print(len(words))
cost time 0.000 secs
['乌合之众', '大众', '心理', '研究', '作者', '古斯塔夫', '勒庞', '法', '本书', '几乎', '从头到尾', '表现', '出', '一种', '对', '重要', '问题', '的', '敏感性', '用', '大法官', '霍尔姆', '斯', '先生', '的话', '说', '勒庞', '在', '这', '本书']
60947
运行结果表明,jieba模块能够在1ms之内给出分词结果。第一次进行分词测试时,很容易让人以为程序运行出错才会出现这种情况,毕竟这本书的文本至少也有近十万字。因此,将分词之后的部分结果打印出来,确保分词处理是正常运行的。
2. SnowNLP模块
jieba模块的运行速度有些让人措手不及,但是SnowNLP模块的耗时就让人放心多了。这个工具也需要使用pip3 install snownlp指令安装,然后就可以在python代码中导入使用了。还是使用《好了歌》作为测试对象。
from snownlp import SnowNLP
words = SnowNLP(text_haole)
print(words.words)
['世人', '都', '晓神', '仙', '好', ',', '惟有', '功', '名', '忘', '不', '了', '!', '古今将相', '在', '何', '方', '?', '荒', '冢', '一', '堆', '草', '没', '了', '。', '世人', '都', '晓神', '仙', '好', '只有', '金银', '忘', '不', '了', '!', '终', '朝', '只', '恨聚', '无', '多', ',', '及', '到', '多', '时', '眼', '闭', '了', '。', '世人', '都', '晓神', '仙', '好', ',', '只有', '姣', '妻', '忘', '不', '了', '!', '君生', '日日', '说', '恩情', ',', '君', '死', '又', '随人', '去', '了', '。', '世人', '都', '晓神', '仙', '好', ',', '只', '有', '儿孙', '忘', '不', '了', '!', '痴心', '父母', '古来', '多', ',', '孝', '顺', '儿孙', '谁见', '了', '?']
从分词的结果来看,SnowNLP给出的分词过于碎,导致一些明显应该作为词的多个字被分开。在运行这个简短的分词时就已经能够感受到SnowNLP模块比jieba模块慢很多。具体的耗时测试更是明确了这种差距。还是使用《乌合之众》的中文翻译测试。
start_time = time.time()
words = SnowNLP(text_crowd)
words = words.words
print('cost time {:.3f} secs'.format(time.time()-start_time))
print(len(words))
cost time 504.477 secs
70324
结果表明,其耗时将近10分钟,而且得到的分词数量比jieba模块的结果更多,即这款工具将文本切分地更加细碎。从直观的表现而言,我更倾向于使用jieba模块。
3. thulac模块
清华大学也出了一款分词工具thulac,该分词模块依赖的模型文件在pip3 install thulac安装时会自动下载,因此不建议使用源码安装。这款分词工具在切分《好了歌》文本时表现如何呢?
import thulac
thu = thulac.thulac(seg_only=True)
words = thu.cut(text_haole, text=True)
print(words)
Model loaded succeed
世人 都 晓神仙 好 , 惟有 功名 忘 不 了 ! 古今 将 相 在 何方 ? 荒冢 一 堆 草没 了 。
世人 都 晓神仙 好 只 有 金银 忘 不 了 ! 终朝 只 恨 聚 无 多 , 及 到 多时 眼 闭 了 。
世人 都 晓神仙 好 , 只有 姣妻 忘 不 了 ! 君生 日日 说 恩情 , 君死 又 随 人 去 了 。
世人 都 晓神仙 好 , 只 有 儿孙 忘 不 了 ! 痴心 父母 古 来 多 , 孝顺 儿孙 谁 见 了 ?
从分词结果来看基本符合预期,能够将明显应该作为词的字划分到一起。到这里似乎觉得这款工具还是不错的,但是接下来的测试让人大跌眼镜。
start_time = time.time()
thu = thulac.thulac(seg_only=True)
words = thu.cut(text_crowd[:50000], text=True)
print('cost time {:.3f} secs'.format(time.time()-start_time))
print(len(words.split(' ')))
Model loaded succeed
larger than max
cost time 26.415 secs
28067
这款工具无法处理过长的文本,估计处理长度在5万到6万之间,超过长度会报赋值失败的错误。我们将文本长度截断之后,该工具运行时间倒是还勉强可以接受。就实际使用而言,这款工具在分切长文本的缺陷让人不敢轻易采用。
4. pyltp模块
接下来出场的一款工具是pyltp,在安装和测试时,这款工具表现出两个麻烦点:1.分词模型文件需要单独下载,2.安装过程需要修改源代码。模型文件和源码都可以从github上的HIT-SCIR/pyltp仓库中获取。对MacOS,pyltp模块的setup.py文件中会检查环境变量MACOSX_DEPLOYMENT_TARGET,默认没有配置这个环境变量的情况下,可能会报错。对于mojave系统,需要运行指令export MACOSX_DEPLOYMENT_TARGET=10.14,对于10.13的系统也需要进行对应修改。这样处理之后,在python3.7环境下安装时还是会报错,报错信息显示无法完成const char * 到void *的自动类型转换,因此需要进行强制数据类型转换。修改文件patch/libs/python/src/converter/builtin_converters.cpp的第51行为强制数据类型转换,return (void *)(PyUnicode_Check(obj) ? _PyUnicode_AsString(obj) : 0);。修改你之后与修改之前的差异如下图所示。

或许在看到这些麻烦之后,大家就没有兴趣再去体验这个分词工具了。这里还是给出一下测试结果,毕竟花了老大的劲才把它装上。还是使用《好了歌》做分词效果测试。
from pyltp import Segmentor
import os
HOME_DIR = os.path.expanduser('~')
seg = Segmentor()
seg.load(os.path.join(HOME_DIR, 'CodeStudio/python/env/models/ltp_data_v3.4.0/cws.model'))
words = seg.segment(text_haole)
print(','.join(words))
seg.release()
世人,都,晓,神仙,好,,,惟有,功名,忘,不,了,!,古今,将,相,在,何方,?,荒,冢,一,堆,草,没,了,。
,世人,都,晓,神仙,好,只,有,金银,忘,不,了,!,终朝,只,恨,聚,无,多,,,及,到,多时,眼,闭,了,。
,世人,都,晓,神仙,好,,,只有,姣妻,忘,不,了,!,君生,日日,说,恩情,,,君死,又,随,人,去,了,。
,世人,都,晓,神仙,好,,,只,有,儿孙,忘,不,了,!,痴心,父母,古,来,多,,,孝顺,儿孙,谁,见,了,?
测试结果显示,分词工具对词的识别能力还是不够强,但是本该连成词的单字被划分。与jieba工具相比,pyltp工具并没有什么优势。下面的速度测试倒是表现不错,如果愿意克服安装时的一些麻烦,倒是可以尝试一下。
seg = Segmentor()
seg.load(os.path.join(HOME_DIR, 'CodeStudio/python/env/models/ltp_data_v3.4.0/cws.model'))
start_time = time.time()
words = seg.segment(text_crowd)
print('cost time {:.3f} secs'.format(time.time()-start_time))
print(len(list(words)))
seg.release()
cost time 1.007 secs
64676
从以上测试这四款分词工具可以看出,jieba模块确实具有无与伦比的优势,因此对于分词需求首选jieba模块。那么是不是其他模块就如此一无是处呢?当然并不是。这里只是测试了分词功能,这是jieba模版的强项。其他模块除了分词功能,还可以进行词性标注。所以,如果需要进行词性标注的话,另外的三个模块也是可以尝试的。
到此,四款分词工具的测试就结束了。

COMMENT
博客评论区功能由Github Issue提供,提交Issue时请以本文标题为话题。
"BG55-分词工具哪家强?文本分析的利器"