前端开发人员不容错过:分词原理、算法及其适用场景

题图:by Lucas Davies

前端开发人员不容错过:分词原理、算法及其适用场景

一、前言

分词,我认为大多数大前端开发人员都不会接触到这个概念。不过,这并不影响我们去了解它,因为我们需要多方向发展。今天就简单介绍一些分词,我会用简洁的语言来描述这个概念,最后还会提供一个解决方案,希望能对你有所帮助。

分词简单来说就是将一句话依据词义分割成一个个单独的词。这样说或许感受不深,那就先来看它适用的场景。分词是文本挖掘的基础,一般会在自然语言处理、分词搜索、推荐等领域被使用。

二、分词的原理和算法2.1 什么是分词

先理解一下分词的概念。

分词是把连续的字序列按照一定规范重新组合成词序列的行为。在英文里,单词之间是以空格当作分割符,从而把词和词分隔开。然而对于中文来说,并没有一个明显的分割符。

因为缺乏这种显式的分割符,所以在对中文中的词进行分割时会出现很多偏差。

2.2 分词的算法

中文分词存在一定难度,然而也有较为成熟的解决办法。目前的分词算法,大致可以分成以下三类:

1. 基于字符串匹配的分词算法

这种分词方法被称作机械分词算法。它会预先维护一个较大的字典。接着,把句子和字典中的词进行匹配。如果匹配成功,就能够进行分词处理。

它实际上会更复杂一些,这是因为字典足够大时会涉及不同的匹配算法,这里不展开讲。通常是基于 Trie 树结构来实现高效的词图扫描。

2. 基于理解的分词算法

这种分词方法,让计算机去模拟人对句子的理解,以此达到识别词组的效果。其基本思想是,在分词的同时进行句法和语义的分析,并且利用句法和语义信息来处理歧义现象。

它一般包含三部分:有分词子系统,还有句法语义子系统以及总控部分。在总控部分的统筹之下,分词子系统能够获取关于词、句子等方面的句法和语义信息,以此对分词歧义作出判断,也就是说它模拟了人理解句子的过程。因为汉语语言知识具有笼统性和复杂性,很难把各种语言信息整理成机器可以直接读取的形式,所以当下基于理解的分词系统仍处于试验阶段。

3. 基于统计的分词算法

给出大量已经分词的文本,通过利用统计机器学习模型来学习词语切分的规律,这个过程被称为训练,进而能够实现对未知文本的切分。

大规模语料库建立起来了,统计机器学习方法得到了研究和发展,基于统计的中文分词方法渐渐成为主流方法。

2.3 分词的诉求

分词的算法讲解起来较为简单。然而,从现有的经验去看,几乎找不到通用且效果极佳的分词系统。

每个领域都有其自身独特的词汇,这使得通过有限的训练数据很难将所有的语言特征都捕捉到。比如,用人民日报来进行训练的分词系统,在面对网络玄幻小说时,其分词的效果就不会很理想。

这是必然的,在分词系统中,没有银弹。

不同的场景,其对分词的要求有着很大的差异。一般来说,可以从两个方面来进行区分,一是分词的速度,二是分词的准确性。

分词搜索时,对速度的要求比准确性的要求高。而在一些问答系统中,需要对文本有较深的理解,此时准确性的要求高于速度的要求。

不同领域和使用场景对分词有不同要求,因此不能片面理解分词准确率。随着新词增加和训练数据变化,分词准确率会波动。这就是现在吹嘘分词准确率的公司越来越少的原因。

2.4 分词的解决方案

分词具有能够解决实际问题的功能。在经历了如此长的时间并经过反复的迭代更新之后,市面上诞生了一批具有特色的分词系统。比如 IK、Jieba、Ansj、Hanlp、Stanford 分词等。

如果你有兴趣,可以逐个去了解。接下来,我们针对其中的一个开源库 Jieba 来进行讲解。

三、jieba3.1 jieba 的优点

jieba 是开源的。它在 Python 领域中,被宣称是最好的中文分词组件。同时,它基于 MIT 协议,让使用者无需有后顾之忧。

jieba 使用起来较为简单,只需几行代码,便能实现分词调用以及词性标注,并且其速度也较为不错。

它内部有一个词典,这个词典是通过对人民日报进行分析而获得的。对于超出该词典范围的新词,会依据 HMM 模型来进行识别。

它提供三种分词模式。其中一种是精准模式,另一种是全模式,还有一种是搜索模式。全模式能够找到所有可能的词语。搜索模式是在精确模式的基础上,对长词进行切分,以此来提高分割率。

精确模式在分词速度方面,能够达到 400KB/s。全模式下,其分词速度能达到 1.5MB/s。并且,除了 Python 版本之外,还有不同的人以 Python 版的 jieba 为基础,将其扩展出多种语言的实现,这些语言包括:JavaScript、Java、Golang、R、PHP 等。

jieba 的使用

jieba 的代码兼容 Python 2 和 Python 3。在使用之前,需通过命令“pip install jieba”或者“pip3 install jieba”来进行安装。

具体的 Api 情况,在此不做详细阐述。倘若你有兴趣,能够前往 Github 上查看相关文档,文末附有其地址。

这里提供一个简单的代码示例,用以感受 jieba 的便捷与强大。

# encoding=utf-8
import jieba
我进行了分词操作,使用的是 jieba 库,并且设置了 cut_all=True 模式,对“我来到北京清华大学”这句话进行分词,得到的分词结果是 seg_list 。
打印("全模式: " + 用"/"连接(seg_list))
jieba 对“我来到北京清华大学”进行分词,cut_all=False 时,得到的 seg_list 为:["我", "来到", "北京", "清华大学"]
print("默认模式:" + "/".join(seg_list))  # 精确模式
这个地方是网易杭研大厦。
print(", ".join(seg_list))
小明毕业于中国科学院计算所,且是硕士学历。之后他前往日本京都大学进行深造。
print(", ".join(seg_list))

输出的结果:

我来到了大学。
【精确模式】: 我/ 来到/ 北京/ 清华大学
他来到了网易的大厦。这里的“杭研”虽然未在词典中,但被 Viterbi 算法识别出来了。
小明是硕士。他毕业于中国科学院计算所。之后,他前往日本京都大学深造。

前面提到过,jieba 自己维护着一个词组的字典。如果自身的需求中有专有名词需要拆分,那么还可以通过 jieba.Tokenizer(dictionary=DEFAULT_DICT)来自定义一个字典信息。

3.2 jieba 的分词算法

匹配的算法较为复杂,在此就不详细阐述了。现在简单为大家介绍一下 jiaba 分词匹配的原理。

jieba 分词自带一个 dict.txt 词典,此词典中有 2 万多个词条,这些词条包含出现的次数和词性。该词典是作者基于人民日报为主的资料训练出来的。

jieba 会先把这个词典里的数据放置到一个 Trie 树当中。Trie 树是很有名的前缀树。当一个词语的前面几个字相同的时候,就表明它们具有相同的前缀。这样就可以利用 Trie 树来进行存储,它具有查找速度快的优点。

其次,在要对句子进行分词操作时,依据前面生成的 Trie 数,生成有向无环图(DAG)。这一步的意义在于,能够消除分词过程中的歧义,提升切分的准确度,并且找出这句话里所有可能的词。

到这一步,基本上就完成了。对于字典中记录的所有词,都进行了分词的过程。

但是如果你删除了 dict.txt 这个字典,jieba 依然能够进行分词。只是它拆分出来的词,大部分的长度是 2。这是因为,对于那些未被收录在字典中的词,会基于隐马尔科夫模型(HMM)来进行分词预测,并且使用的是 Viterbi 算法。

HMM 模型中,对中文词汇用 BEMS 四个状态进行标记。B 表示开始位置,E 表示结束位置,M 表示中间位置,S 表示单独成词的位置,且无前后。也就是说,它用(B,E,M,S)这四种状态来标记中文词语。例如,“北京”可标注为 BE,即“北/B 京/E”,表明“北”是开始位置,“京”是结束位置;“中华民族”可标注为 BMME,即开始、中间、中间、结束。

作者对大量语料进行了训练,从而得到了 finalseg 目录下的训练结果,若有兴趣可自行进行研究。

3. 最后进行语义分析,根据词语的词性和上下文关系,对词语进行进一步的处理和理解。

加载 dict.txt 字典,接着生成 Trie 树。对于分词的句子,借助 Trie 树来生成 DAG 图,从而匹配出所有可能的词。之后使用 HMM 模型,把字典中未收录的词匹配出来。

这就是 jieba 分词的执行过程。

四、jieba(Java 或 Android)的 4.1 Java 版,即关于 Java 版本的 jieba

jieba 发展至今,支持着众多的版本。Java 版并非由原作者开发,而是 hanban 依据原作者的分词原理进行开发的。

Java 版的功能没有原版 Python 版本那么强,它进行了部分删减。比如在关键词提取方面就没有实现。

有兴趣可以直接去看 Github :

1. 引入依赖(稳定版)


  com.huaban
  jieba-analysis
  1.0.2

2. 如何使用

@Test
public void testDemo() {
创建了一个 JiebaSegmenter 的实例,名为 segmenter 。
    String[] sentences =
雷猴重新回到了人间。
工信处女干事每月经过下属科室时,都要亲口交代关于 24 口交换机等技术性器件的安装工作。同时,涉及到的人员有已婚的和尚未结婚的。
对于每一个字符串 sentence ,它都在 sentences 这个集合之中 。
System.out 会打印出 segmenter 对 sentence 进行处理(使用 SegMode.INDEX 模式)的结果,并将其转换为字符串形式。
    }
}

3. 性能评估

作者在测试机上进行测试,配置为:

处理器 2 为英特尔奔腾 CPU G620,其主频为 2.60GHz。
Memory:8GB

测试结果较为理想,在单线程的情况下,对测试文本逐行进行分词操作,并且循环调用上万次,以此来进行效率分析。

循环调用一万次
第一次测试结果:
时间经过了 12373,速率是 2486.986533kb/s,字数是 917319.94/s
第二次测试结果:
时间经过了 12284,速率是 2505.005241kb/s,字数是 923966.10/s
第三次测试结果:
时间经过了 12336,速率是 2494.445880kb/s,字数是 920071.30/s
循环调用2万次
第一次测试结果:
时间经过了 22237,速率是 2767.593144kb/s,字数是 1020821.12/s
第二次测试结果:
时间经过了 22435,速率是 2743.167762kb/s,字数是 1011811.87/s
第三次测试结果:
时间经过了 22102,速率是 2784.497726kb/s,字数是 1027056.34/s
统计结果表明,词典加载大概需要 1.8 秒,分词的效率每秒超过 2Mb,总共处理了近 100 万词。
处理器为英特尔(Intel)酷睿(Core)i3 - 2100 中央处理器,其运行频率为 3.10GHz。
12G 测试效果
时间经过了 19597,速率是 3140.428063kb/s,字数是 1158340.52/s
时间经过了 20122,速率是 3058.491639kb/s,字数是 1128118.44/s

4.2 在 Android 下使用 jieba

jieba(Java)版本自带词典,在 Android 下引入此版本会增大 Apk 的体积,目前没有很好的规避办法。并且由于设备配置的原因,还会对分词的效率产生影响。

如果非要在 Android 设备上使用的话,比如对搜索词进行预先处理,这是可以做到的。

jieba(java)是以 maven 来进行管理的,因此需要对 Gradle 进行简单的配置,以便使其能够得到支持。

1. 配置 build.gradle

repositories {
    google()
    jcenter()
    mavenCentral()
}

2. 引入依赖

api 为 'com.huaban:jieba-analysis:1.0.2' 。

引入之后,关于使用细节就没有什么可特别提及的了,它与 Java 版本是没有差别的。

参考:

推荐我的知识星球,这里有“联机圆桌”活动。一年能提供 50 个优质问题,大家可以上桌一起联机学习。

在公众号后台回复“成长”,你将会获得我准备的学习资料;同时,你也可以回复“加群”,以便一起学习进步;此外,你还能够回复“提问”,向我发起提问。

你可能想看:
« 上一篇
下一篇 »

相关推荐

python爬虫教程PDF,Python爬虫书PDF

2026年09月02日

30阅读

外国教程python,python编程教学视频

2026年09月02日

24阅读

python简明教程沈洁元,python详细基础教程

2026年09月02日

21阅读

python库包教程,python 包

2026年09月02日

26阅读

python教程大全集,python教程600集

2026年09月02日

26阅读

python入门教程完整版,python零基础入门全套教程视频

2026年09月02日

22阅读