題圖:by Lucas Davies前端
分詞,我想是大多數大前端開發人員,都不會接觸到的一個概念。這個不影響咱們瞭解它,畢竟咱們要多方向發展。今天就來簡單介紹一些分詞,我儘可能用簡介的語言來描述這個概念,而且最後再提供一個解決方案,但願對你有幫助。java
分詞簡單來說就是把一句話,按照詞義,切分紅一個個單獨的詞。這麼說可能沒什麼感受,先看看它適用的場景。分詞是文本挖掘的基礎,一般會用於天然語言處理、分詞搜索、推薦等等領域。python
先理解一下分詞的概念。nginx
分詞就是將連續的字序列按照必定的規範從新組合成詞序列的過程。在英文中,單詞之間會以空格做爲分割符,將詞與詞之間進行分割,可是對於中文,沒有一個顯式的分割符。git
正是由於缺少這種顯式的分割符,致使咱們對中文中的詞,進行分割的時候會出現不少的誤差。github
中文分詞有難度,不過也有成熟的解決方案。現有的分詞算法,大概可分爲三類:算法
1. 基於字符串匹配的分詞算法小程序
這種分詞方法,又叫機械分詞算法,它會提早維護一個大的字典,而後將句子和字典中的詞進行匹配,若匹配成功,則能夠進行分詞處理。api
固然,它實際上會更復雜一些,由於當字典足夠大的時候,就又涉及到不一樣的匹配算法,這裏就不展開講了。一般會基於 Trie 樹結構,來實現高效的詞圖掃描。緩存
2. 基於理解的分詞算法
這種分詞方法,經過讓計算機,模擬人對句子的理解,達到識別詞組的效果。其基本思想是在分詞的同事進行句法、語義的分析,利用句法和語義信息來處理歧義現象。
它一般會包含三部分:分詞子系統、句法語義子系統、總控部分。在總控部分的協調下,分詞子系統能夠得到有關詞、句子等的句法和語義信息,來對分詞歧義進行判斷,即它模擬了人對句子的理解過程。因爲漢語語言知識的籠統、複雜性,難以將各類語言信息組織成機器可直接讀取的形式,所以目前基於理解的分詞系統還處在試驗階段。
3. 基於統計的分詞算法
給出大量已經分詞的文本,利用統計機器學習模型學習詞語切分的規律(稱爲訓練),從而實現對未知文本的切分。
隨着大規模語料庫的創建,統計機器學習方法的研究和發展,基於統計的中文分詞方法漸漸成爲了主流方法。
雖然分詞的算法,講解起來很簡單,可是從現有的經驗來看,幾乎是不存在通用且效果很是好的分詞系統。
每一個領域,都有其獨特的詞彙,這很難經過有限的訓練數據,捕捉到全部的語言特徵。例如:經過人民日報訓練的分詞系統,在網絡玄幻小說上,分詞的效果就不會好。
這是必然的,在分詞系統中,沒有銀彈。
不一樣的場景,對分詞的要求也差別很大,一般能夠從兩個維度進行區分:分詞速度、分詞準確性。
例如分詞搜索,對速度要求就高於準確性的要求。而一些問答系統中,則須要對文本實現較深的理解,要求準確性高於速度要求。
不一樣的領域,不一樣的使用場景,對分詞的要求是不一樣的,因此咱們不能片面的去理解分詞的準確率。而且隨着新詞的增長,訓練數據的變化,分詞的準確率也是在波動的。這也是爲何,如今吹噓分詞準確率的公司愈來愈少的緣由。
分詞是能夠解決實際問題的功能,通過這麼長時間的反覆迭代更新,市面上一家產生了一批有特點的分詞系統。例如:IK、Jieba、Ansj、Hanlp、Stanford分詞 等等。
有興趣能夠一個個瞭解,接下來就其中的一個開源庫 Jieba,進行講解。
jieba 是開源的,號稱是 Python 中,最好的中文分詞組件。而且是基於 MIT 的協議,使用起來無後顧之憂。
jieba 使用起來也很是的簡單,幾行代碼就能夠實現分詞調用和詞性標註,並且速度還不錯。
它內部維護了一個詞典,是根據人民日報分析得到,在超出詞典以外的新詞,會基於 HMM 模型進行識別。
它提供三種分詞模式:精準模式、全模式、搜索模式。全模式是找到全部可能的詞語,搜索模式是在精確模式的基礎上對長詞進行切分,提升分割率。
在分詞的速度上,精確模式能達到 400KB/s,全模式下能達到 1.5MB/s。同時除了 Python 版本以外,還有不一樣的人基於 Python 版的 jieba ,擴展出多種語言實現,包括:JavaScript、Java、Golang、R、PHP 等。
jieba 的代碼對 Python 2/3 均兼容,在使用以前,須要經過命令 pip install jieba
或者 pip3 install jieba
進行安裝。
具體 Api,就不展開講了,有興趣能夠去查看 Github 上的文檔(文末有地址)。
這裏提供一個簡單的代碼示例,來感覺一下 jieba 的方便與強大。
# encoding=utf-8
import jieba
seg_list = jieba.cut("我來到北京清華大學", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list)) # 全模式
seg_list = jieba.cut("我來到北京清華大學", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精確模式
seg_list = jieba.cut("他來到了網易杭研大廈") # 默認是精確模式
print(", ".join(seg_list))
seg_list = jieba.cut_for_search("小明碩士畢業於中國科學院計算所,後在日本京都大學深造") # 搜索引擎模式
print(", ".join(seg_list))
複製代碼
輸出的結果:
【全模式】: 我/ 來到/ 北京/ 清華/ 清華大學/ 華大/ 大學
【精確模式】: 我/ 來到/ 北京/ 清華大學
【新詞識別】:他, 來到, 了, 網易, 杭研, 大廈 (此處,「杭研」並無在詞典中,可是也被Viterbi算法識別出來了)
【搜索引擎模式】: 小明, 碩士, 畢業, 於, 中國, 科學, 學院, 科學院, 中國科學院, 計算, 計算所, 後, 在, 日本, 京都, 大學, 日本京都大學, 深造
複製代碼
前面也提到,jieba 自身維護了一個詞組的字典,若是自身需求上有專有名詞須要拆分,還能夠經過 jieba.Tokenizer(dictionary=DEFAULT_DICT)
自定義一個字典信息。
匹配的算法,提及來就複雜了,這裏就簡單介紹一下 jiaba 分詞匹配的原理。
首先,jieba 分詞已經自帶了一個 dict.txt 的詞典,裏面有 2w 多個詞條,包括出現的次數和詞性,這是做者本身基於人民日報爲主的資料,訓練的出來的。
jieba 會先將這個詞典中的數據,放到一個 Trie 樹中,Trie 樹是有名的前綴樹,當一個詞語的前面幾個字同樣的時候,就標識他們具備相同的前綴,就可使用 Trie 數來存儲,具備查找速度快的優點。
其次,在須要對句子進行分詞的時候,再根據前面生成的 Trie 數,生成有向無環圖(DAG),這一步的意義在於,消除分詞中的歧義,提升切分準確度,找出這句話中,全部可能的詞。
到這一步,基本上就完成了,全部字典中記錄的詞,進行分詞的過程。
可是若是你把 dict.txt 這個字典刪除,jieba 依然能夠進行分詞,只是拆分出來的詞,大部分的長度爲 2。這是由於,對於未在字典中收錄的詞,基於隱馬爾科夫模型(HMM)來預測分詞,使用的是 Viterbi 算法。
HMM 模型中,將中文詞彙按照 BEMS 四個狀態來標記, B 是開始 begin 位置, E 是 end, 是結束位置, M 是 middle, 是中間位置, S 是 singgle, 單獨成詞的位置, 沒有前, 也沒有後. 也就是說, 他採用了狀態爲(B,E,M,S)這四種狀態來標記中文詞語, 好比北京能夠標註爲 BE, 即 北/B 京/E, 表示北是開始位置, 京是結束位置, 中華民族能夠標註爲 BMME , 就是開始, 中間, 中間, 結束.
做者經過對大量語料的訓練,獲得了 finalseg 目錄下的訓練結果,有興趣能夠自行研究。
到這裏基本上就清晰了,jieba 分詞的過程主要有如下三步:
這就是 jieba 分詞的執行過程。
jieba 發展到如今,已經支持衆多的版本。Java 版並不是原做者開發,而是 hanban 參考原做者的分詞原理,進行開發的。
不過 Java 版並無原版 Python 版本那麼強大,作了部分閹割,例如關鍵詞提取就沒有實現。
有興趣能夠直接去看 Github : https://github.com/huaban/jieba-analysis/
1. 引入依賴(穩定版)
<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[] {"這是一個伸手不見五指的黑夜。我叫孫悟空,我愛北京,我愛Python和C++。", "我不喜歡日本和服。", "雷猴迴歸人間。",
"工信處女幹事每個月通過下屬科室都要親口交代24口交換機等技術性器件的安裝工做", "結果婚的和還沒有結過婚的"};
for (String sentence : sentences) {
System.out.println(segmenter.process(sentence, SegMode.INDEX).toString());
}
}
複製代碼
3. 性能評估
做者在測試機上進行測試,配置爲:
Processor 2 Intel(R) Pentium(R) CPU G620 @ 2.60GHz
Memory:8GB
複製代碼
測試結果還算理想,單線程,對測試文本逐行分詞,並循環調用上萬次的效率分析。
循環調用一萬次
第一次測試結果:
time elapsed:12373, rate:2486.986533kb/s, words:917319.94/s
第二次測試結果:
time elapsed:12284, rate:2505.005241kb/s, words:923966.10/s
第三次測試結果:
time elapsed:12336, rate:2494.445880kb/s, words:920071.30/s
循環調用2萬次
第一次測試結果:
time elapsed:22237, rate:2767.593144kb/s, words:1020821.12/s
第二次測試結果:
time elapsed:22435, rate:2743.167762kb/s, words:1011811.87/s
第三次測試結果:
time elapsed:22102, rate:2784.497726kb/s, words:1027056.34/s
統計結果:詞典加載時間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
複製代碼
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 版本無差異。
參考:
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
公衆號後臺回覆成長『成長』,將會獲得我準備的學習資料,也能回覆『加羣』,一塊兒學習進步;你還能回覆『提問』,向我發起提問。
推薦閱讀:
寫做是核心競爭力 | Google 工程師解密「猜畫小歌」 | 圖解:HTTP 範圍請求 | Android P 適配經驗 | 技術創業選擇清單 | HTTP傳輸編碼 | 什麼正在消耗你? | HTTP 內容編碼 | 圖解 HTTP 緩存 | 聊聊 HTTP 的 Cookie | 輔助模式實戰 | Accessibility 輔助模式 | 小程序 Flex 佈局 | 好的 PR 讓你更靠譜 | 密碼管理之道