
題圖:by Lucas Davies
一、前言
分詞,我想是大多數(shù)大前端開發(fā)人員,都不會(huì)接觸到的一個(gè)概念。這個(gè)不影響我們了解它,畢竟我們要多方向發(fā)展。今天就來簡單介紹一些分詞,我盡量用簡介的語言來描述這個(gè)概念,并且最后再提供一個(gè)解決方案,希望對你有幫助。
分詞簡單來講就是把一句話,按照詞義,切分成一個(gè)個(gè)單獨(dú)的詞。這么說可能沒什么感覺,先看看它適用的場景。分詞是文本挖掘的基礎(chǔ),通常會(huì)用于自然語言處理、分詞搜索、推薦等等領(lǐng)域。
二、分詞的原理和算法
2.1 什么是分詞
先理解一下分詞的概念。
分詞就是將連續(xù)的字序列按照一定的規(guī)范重新組合成詞序列的過程。在英文中,單詞之間會(huì)以空格作為分割符,將詞與詞之間進(jìn)行分割,但是對于中文,沒有一個(gè)顯式的分割符。
正是因?yàn)槿狈@種顯式的分割符,導(dǎo)致我們對中文中的詞,進(jìn)行分割的時(shí)候會(huì)出現(xiàn)很多的偏差。
2.2 分詞的算法
中文分詞有難度,不過也有成熟的解決方案?,F(xiàn)有的分詞算法,大概可分為三類:
- 基于字符串匹配的分詞算法
- 基于理解的分詞算法
- 基于統(tǒng)計(jì)的分詞算法
1. 基于字符串匹配的分詞算法
這種分詞方法,又叫機(jī)械分詞算法,它會(huì)提前維護(hù)一個(gè)大的字典,然后將句子和字典中的詞進(jìn)行匹配,若匹配成功,則可以進(jìn)行分詞處理。
當(dāng)然,它實(shí)際上會(huì)更復(fù)雜一些,因?yàn)楫?dāng)字典足夠大的時(shí)候,就又涉及到不同的匹配算法,這里就不展開講了。通常會(huì)基于 Trie 樹結(jié)構(gòu),來實(shí)現(xiàn)高效的詞圖掃描。
2. 基于理解的分詞算法
這種分詞方法,通過讓計(jì)算機(jī),模擬人對句子的理解,達(dá)到識(shí)別詞組的效果。其基本思想是在分詞的同事進(jìn)行句法、語義的分析,利用句法和語義信息來處理歧義現(xiàn)象。
它通常會(huì)包含三部分:分詞子系統(tǒng)、句法語義子系統(tǒng)、總控部分。在總控部分的協(xié)調(diào)下,分詞子系統(tǒng)可以獲得有關(guān)詞、句子等的句法和語義信息,來對分詞歧義進(jìn)行判斷,即它模擬了人對句子的理解過程。由于漢語語言知識(shí)的籠統(tǒng)、復(fù)雜性,難以將各種語言信息組織成機(jī)器可直接讀取的形式,因此目前基于理解的分詞系統(tǒng)還處在試驗(yàn)階段。
3. 基于統(tǒng)計(jì)的分詞算法
給出大量已經(jīng)分詞的文本,利用統(tǒng)計(jì)機(jī)器學(xué)習(xí)模型學(xué)習(xí)詞語切分的規(guī)律(稱為訓(xùn)練),從而實(shí)現(xiàn)對未知文本的切分。
隨著大規(guī)模語料庫的建立,統(tǒng)計(jì)機(jī)器學(xué)習(xí)方法的研究和發(fā)展,基于統(tǒng)計(jì)的中文分詞方法漸漸成為了主流方法。
2.3 分詞的訴求
雖然分詞的算法,講解起來很簡單,但是從現(xiàn)有的經(jīng)驗(yàn)來看,幾乎是不存在通用且效果非常好的分詞系統(tǒng)。
每個(gè)領(lǐng)域,都有其獨(dú)特的詞匯,這很難通過有限的訓(xùn)練數(shù)據(jù),捕捉到所有的語言特征。例如:通過人民日報(bào)訓(xùn)練的分詞系統(tǒng),在網(wǎng)絡(luò)玄幻小說上,分詞的效果就不會(huì)好。
這是必然的,在分詞系統(tǒng)中,沒有銀彈。
不同的場景,對分詞的要求也差異很大,通??梢詮膬蓚€(gè)維度進(jìn)行區(qū)分:分詞速度、分詞準(zhǔn)確性。
例如分詞搜索,對速度要求就高于準(zhǔn)確性的要求。而一些問答系統(tǒng)中,則需要對文本實(shí)現(xiàn)較深的理解,要求準(zhǔn)確性高于速度要求。
不同的領(lǐng)域,不同的使用場景,對分詞的要求是不同的,所以我們不能片面的去理解分詞的準(zhǔn)確率。并且隨著新詞的增加,訓(xùn)練數(shù)據(jù)的變化,分詞的準(zhǔn)確率也是在波動(dòng)的。這也是為什么,現(xiàn)在吹噓分詞準(zhǔn)確率的公司越來越少的原因。
2.4 分詞的解決方案
分詞是可以解決實(shí)際問題的功能,經(jīng)過這么長時(shí)間的反復(fù)迭代更新,市面上一家產(chǎn)生了一批有特色的分詞系統(tǒng)。例如:IK、Jieba、Ansj、Hanlp、Stanford分詞 等等。
有興趣可以一個(gè)個(gè)了解,接下來就其中的一個(gè)開源庫 Jieba,進(jìn)行講解。
三、jieba
3.1 jieba 的優(yōu)點(diǎn)
jieba 是開源的,號(hào)稱是 Python 中,最好的中文分詞組件。并且是基于 MIT 的協(xié)議,使用起來無后顧之憂。
jieba 使用起來也非常的簡單,幾行代碼就可以實(shí)現(xiàn)分詞調(diào)用和詞性標(biāo)注,而且速度還不錯(cuò)。
它內(nèi)部維護(hù)了一個(gè)詞典,是根據(jù)人民日報(bào)分析獲得,在超出詞典之外的新詞,會(huì)基于 HMM 模型進(jìn)行識(shí)別。
它提供三種分詞模式:精準(zhǔn)模式、全模式、搜索模式。全模式是找到所有可能的詞語,搜索模式是在精確模式的基礎(chǔ)上對長詞進(jìn)行切分,提高分割率。
在分詞的速度上,精確模式能達(dá)到 400KB/s,全模式下能達(dá)到 1.5MB/s。同時(shí)除了 Python 版本之外,還有不同的人基于 Python 版的 jieba ,擴(kuò)展出多種語言實(shí)現(xiàn),包括:JavaScript、Java、Golang、R、PHP 等。
jieba 的使用
jieba 的代碼對 Python 2/3 均兼容,在使用之前,需要通過命令 pip install jieba 或者 pip3 install jieba 進(jìn)行安裝。
具體 Api,就不展開講了,有興趣可以去查看 Github 上的文檔(文末有地址)。
這里提供一個(gè)簡單的代碼示例,來感受一下 jieba 的方便與強(qiáng)大。
# encoding=utf-8
import jieba
seg_list = jieba.cut("我來到北京清華大學(xué)", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list)) # 全模式
seg_list = jieba.cut("我來到北京清華大學(xué)", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精確模式
seg_list = jieba.cut("他來到了網(wǎng)易杭研大廈") # 默認(rèn)是精確模式
print(", ".join(seg_list))
seg_list = jieba.cut_for_search("小明碩士畢業(yè)于中國科學(xué)院計(jì)算所,后在日本京都大學(xué)深造") # 搜索引擎模式
print(", ".join(seg_list))
輸出的結(jié)果:
【全模式】: 我/ 來到/ 北京/ 清華/ 清華大學(xué)/ 華大/ 大學(xué)
【精確模式】: 我/ 來到/ 北京/ 清華大學(xué)
【新詞識(shí)別】:他, 來到, 了, 網(wǎng)易, 杭研, 大廈 (此處,“杭研”并沒有在詞典中,但是也被Viterbi算法識(shí)別出來了)
【搜索引擎模式】: 小明, 碩士, 畢業(yè), 于, 中國, 科學(xué), 學(xué)院, 科學(xué)院, 中國科學(xué)院, 計(jì)算, 計(jì)算所, 后, 在, 日本, 京都, 大學(xué), 日本京都大學(xué), 深造
前面也提到,jieba 自身維護(hù)了一個(gè)詞組的字典,如果自身需求上有專有名詞需要拆分,還可以通過 jieba.Tokenizer(dictionary=DEFAULT_DICT) 自定義一個(gè)字典信息。
3.2 jieba 的分詞算法
匹配的算法,說起來就復(fù)雜了,這里就簡單介紹一下 jiaba 分詞匹配的原理。
首先,jieba 分詞已經(jīng)自帶了一個(gè) dict.txt 的詞典,里面有 2w 多個(gè)詞條,包括出現(xiàn)的次數(shù)和詞性,這是作者自己基于人民日報(bào)為主的資料,訓(xùn)練的出來的。
jieba 會(huì)先將這個(gè)詞典中的數(shù)據(jù),放到一個(gè) Trie 樹中,Trie 樹是有名的前綴樹,當(dāng)一個(gè)詞語的前面幾個(gè)字一樣的時(shí)候,就標(biāo)識(shí)他們具有相同的前綴,就可以使用 Trie 數(shù)來存儲(chǔ),具有查找速度快的優(yōu)勢。
其次,在需要對句子進(jìn)行分詞的時(shí)候,再根據(jù)前面生成的 Trie 數(shù),生成有向無環(huán)圖(DAG),這一步的意義在于,消除分詞中的歧義,提高切分準(zhǔn)確度,找出這句話中,所有可能的詞。
到這一步,基本上就完成了,所有字典中記錄的詞,進(jìn)行分詞的過程。
但是如果你把 dict.txt 這個(gè)字典刪除,jieba 依然可以進(jìn)行分詞,只是拆分出來的詞,大部分的長度為 2。這是因?yàn)?,對于未在字典中收錄的詞,基于隱馬爾科夫模型(HMM)來預(yù)測分詞,使用的是 Viterbi 算法。
HMM 模型中,將中文詞匯按照 BEMS 四個(gè)狀態(tài)來標(biāo)記, B 是開始 begin 位置, E 是 end, 是結(jié)束位置, M 是 middle, 是中間位置, S 是 singgle, 單獨(dú)成詞的位置, 沒有前, 也沒有后. 也就是說, 他采用了狀態(tài)為(B,E,M,S)這四種狀態(tài)來標(biāo)記中文詞語, 比如北京可以標(biāo)注為 BE, 即 北/B 京/E, 表示北是開始位置, 京是結(jié)束位置, 中華民族可以標(biāo)注為 BMME , 就是開始, 中間, 中間, 結(jié)束.
作者通過對大量語料的訓(xùn)練,得到了 finalseg 目錄下的訓(xùn)練結(jié)果,有興趣可以自行研究。
到這里基本上就清晰了,jieba 分詞的過程主要有以下三步:
- 加載 dict.txt 字典,生成 Trie 樹。
- 對待分詞的句子,通過 Trie 樹,生成 DAG 圖,匹配出所有可能的詞。
- 再使用 HMM 模型,將字典中未收錄的詞,匹配出來。
這就是 jieba 分詞的執(zhí)行過程。
四、jieba(Java or Android)
4.1 Java 版的 jieba
jieba 發(fā)展到現(xiàn)在,已經(jīng)支持眾多的版本。Java 版并非原作者開發(fā),而是 hanban 參考原作者的分詞原理,進(jìn)行開發(fā)的。
不過 Java 版并沒有原版 Python 版本那么強(qiáng)大,做了部分閹割,例如關(guān)鍵詞提取就沒有實(shí)現(xiàn)。
有興趣可以直接去看 Github : https://github.com/huaban/jieba-analysis/
1. 引入依賴(穩(wěn)定版)
<dependency>
<groupId>com.huaban</groupId>
<artifactId>jieba-analysis</artifactId>
<version>1.0.2</version>
</dependency>
2. 如何使用
@Test
public void testDemo() {
JiebaSegmenter segmenter = new JiebaSegmenter();
String[] sentences =
new String[] {"這是一個(gè)伸手不見五指的黑夜。我叫孫悟空,我愛北京,我愛Python和C++。", "我不喜歡日本和服。", "雷猴回歸人間。",
"工信處女干事每月經(jīng)過下屬科室都要親口交代24口交換機(jī)等技術(shù)性器件的安裝工作", "結(jié)果婚的和尚未結(jié)過婚的"};
for (String sentence : sentences) {
System.out.println(segmenter.process(sentence, SegMode.INDEX).toString());
}
}
3. 性能評(píng)估
作者在測試機(jī)上進(jìn)行測試,配置為:
Processor 2 Intel(R) Pentium(R) CPU G620 @ 2.60GHz
Memory:8GB
測試結(jié)果還算理想,單線程,對測試文本逐行分詞,并循環(huán)調(diào)用上萬次的效率分析。
循環(huán)調(diào)用一萬次
第一次測試結(jié)果:
time elapsed:12373, rate:2486.986533kb/s, words:917319.94/s
第二次測試結(jié)果:
time elapsed:12284, rate:2505.005241kb/s, words:923966.10/s
第三次測試結(jié)果:
time elapsed:12336, rate:2494.445880kb/s, words:920071.30/s
循環(huán)調(diào)用2萬次
第一次測試結(jié)果:
time elapsed:22237, rate:2767.593144kb/s, words:1020821.12/s
第二次測試結(jié)果:
time elapsed:22435, rate:2743.167762kb/s, words:1011811.87/s
第三次測試結(jié)果:
time elapsed:22102, rate:2784.497726kb/s, words:1027056.34/s
統(tǒng)計(jì)結(jié)果:詞典加載時(shí)間1.8s左右,分詞效率每秒2Mb多,近100萬詞。
2 Processor Intel(R) Core(TM) i3-2100 CPU @ 3.10GHz
12G 測試效果
time elapsed:19597, rate:3140.428063kb/s, words:1158340.52/s
time elapsed:20122, rate:3058.491639kb/s, words:1128118.44/s
4.2 在 Android 下使用 jieba
jieba(Java)版本,本身也是自帶詞典的,所以在 Android 下引入,會(huì)增大 Apk 的體積,這沒有什么很好的規(guī)避方法。而且因?yàn)樵O(shè)備的配置,還會(huì)影響到分詞的效率。
不過如果非要使用在 Android 設(shè)備上,例如對搜索詞進(jìn)行一個(gè)預(yù)處理,也是可以的。
jieba(java) 使用 maven 管理,所以需要 Gradle 簡單配置一下,讓其支持。
1. 配置 build.gradle
repositories {
google()
jcenter()
mavenCentral()
}
2. 引入依賴
api 'com.huaban:jieba-analysis:1.0.2'
引入之后,使用細(xì)節(jié)就沒什么好說的了,和 Java 版本無差別。
參考:
https://github.com/fxsjy/jieba
https://github.com/huaban/jieba-analysis/
https://blog.csdn.net/John_xyz/article/details/54645527
http://www.infoq.com/cn/articles/nlp-word-segmentation
「聯(lián)機(jī)圓桌」??推薦我的知識(shí)星球,一年 50 個(gè)優(yōu)質(zhì)問題,上桌聯(lián)機(jī)學(xué)習(xí)。
公眾號(hào)后臺(tái)回復(fù)成長『成長』,將會(huì)得到我準(zhǔn)備的學(xué)習(xí)資料,也能回復(fù)『加群』,一起學(xué)習(xí)進(jìn)步;你還能回復(fù)『提問』,向我發(fā)起提問。
推薦閱讀:
寫作是核心競爭力 | Google 工程師解密“猜畫小歌” | 圖解:HTTP 范圍請求 | Android P 適配經(jīng)驗(yàn) | 技術(shù)創(chuàng)業(yè)選擇清單 | HTTP傳輸編碼 | 什么正在消耗你? | HTTP 內(nèi)容編碼 | 圖解 HTTP 緩存 | 聊聊 HTTP 的 Cookie | 輔助模式實(shí)戰(zhàn) | Accessibility 輔助模式 | 小程序 Flex 布局 | 好的 PR 讓你更靠譜 | 密碼管理之道
