1. 現在就由我來跟各位介紹一下 Jieba 這個中文斷詞程式。Jieba 這個中文斷詞程式是由中國百度的一個開發者寫的,所以呢,它的核心其實是簡體中文,不過因為它是一個開放原始碼的 Project,任何人都可以幫忙修改這個斷詞程式,我就幫它加上了繁體中文字典,目前 Jieba 已經可以支援簡體和繁體中文了。
2. 好,那跟各位介紹一下我自己,我是林志傑,網路上常用的名字是 Fukuball,所以各位可以用 Fukuball 這個關鍵字找到我。我以前也在政大唸書,所以畢業後還可以回來母校分享一些事情感覺蠻開心的。我目前在 iNDIEVOX 獨立音樂網工作,這個網站主要專注於台灣獨立音樂相關的電子商務服務,獨立音樂人可以在這邊上傳他們的作品、或販售演唱會票券,樂迷就可以在這邊直接購買到創作者的數位音樂及演唱會票券,我們希望可以透過這個平台,讓台灣的獨立音樂生態可以像國外的獨立音樂那樣完善。所以大家有空也可以來 iNDIEVOX 上面逛逛、聽聽音樂~
3. 那,我們開始進入正題。究竟 Jieba 是什麼呢?Jieba 是一個中文斷詞程式,在中國他們叫分詞,我覺得作者把這個程式的名字取得很好,因為當我們將一句話斷成詞的時候,念起來就會像是結巴一樣,所以我覺得這個名字取得很有意義。那中文斷詞到底要做什麼呢?其實當我們要用電腦做自然語言處理或是進行文本分析研究的時候,通常需要先將文本進行斷詞,用詞這個最小且有意義的單位來進行分析、整理,因此斷詞可以說是整個自然語言處理最基礎的工作。做好斷詞這項工作,我們才可以進一步發展出問答系統、自動摘要、文件檢索、機器翻譯、語音辨識等等功能。
4. 這裡讓我們來說明一下中文斷詞有什麼特別的地方(說明投影片)
5. 有人會問,中研院也有中文斷詞系統啊,那為何還要選擇使用 Jieba?
6. 其實曾經我也使用中研院斷詞系統,但使用過後才發覺問題很大,首先中研院斷詞系統很不穩定,常常回傳的資料有可能會有被截斷的情況,然後 API 也不夠完善,當功能不夠完整的時候,開發者就會想要去把它修改得更好,但中研院斷詞系統並非開源的 Project,我們也無法調整它,讓這個斷詞系統可以變得更好用,所以最後只能往外尋找其他的資源。
7. 後來就看到了 Jieba 這個斷詞程式,它最大的優點就是它是一個 open source 的 project,我們可以預期未來會有更多優秀的開發者加入開發 Jieba,Jieba 也會因為優秀開發者的加入而讓功能變得越來越完善,所以使用 Jieba 會是一個很好的選擇。
8. 我這邊大概整理了 Jieba 這個斷詞程式核心演算法如何運作的概觀,這是 Jieba 各個部份演算法大致的架構及處理流程,首先呢,我們輸入要進行斷詞的句子,這邊我們用 Jieba 它所提供的例子來說明,我們要將「終於,他來到了網易杭研大廈」這個句子進行斷詞,第一步就是使用正規式來將符號與文字切開,如此就會先斷成像投影片所顯示的這三個部分,第一個部分是「終於」,第二個部分是逗號,第三個部分是「他來到了網易杭研大廈」,然後結巴會把屬於文字的部分進行進一步的處理。第二步 Jieba 會載入字典,建立一個 Trie 字典樹,等一下我們會詳細說明 Trie 字典樹的結構長什麼樣子,有了 Trie 字典樹之後,Jieba 就開始比對句子中有沒有 Trie 字典樹中的詞,然後計算出句子有幾種切分組合,再把切分組合表示成一個有向無環圖,大致上這個無環圖可以這樣表示,(解釋),第三步再計算最佳的切分組合是什麼(解釋),在這邊我們就可以得到一個還不錯的結果,最後一步呢,我們看到有連續的單字詞出現,比如這個例子裡斷出的「杭」及「研」這個兩個單字詞,這時我們就可以把這些單字詞再組合起來丟到 HMM Viterbi 演算法計算看看是否能組成一個新的詞,計算結果是,「杭研」可以再組成一個詞,這就是整個 Jieba 斷詞程式的運作過程。我接下來會稍微介紹一下各部分演算法的概念,但詳細的演算法因為時間的關係就無法在這邊直接說明,其實了解演算法的概念及思路對大家比較有幫助。
9. 由剛剛的 Jieba 核心程式概觀,我們可以知道 Jieba 斷詞是先用字典來解決大部份的斷詞,我們可以稍微看一下原始碼中的字典,(翻開原始碼),字典的格式是長這樣,Jieba 會載入這個字典,然後建立 Trie 樹,Trie 樹又可以叫做前綴樹、字典樹,它可以增加字詞比對的速度,Trie 樹的結構就是我投影片上畫出來的這個圖,上面會有每個字詞及它的機率值,程式在比對的時候,比如句子中出現了「即」這個字,那我們就可以得到 0.1 這個機率值,然後再把句子的下個字往後比對,如果剛好是「將」這個字,那就會得到 0.3 這個機率值,這兩個都算合法的斷詞結果,程式會把它記下來,然後就可以組合成底下這樣的有向無環圖,記錄了所有的斷詞切分組合。
10. 我們可以用爬樓梯來說明剛才字典比對的斷詞過程,當我們要爬到第五階這個階梯時,可能可以從第四階走一步爬到第五階,也可能可以從第三階跨兩步直接爬到第五階,以此類推我們可以計算出所有爬到第五階的走法,這就跟斷詞一樣,會有多種不同的斷法,只是 Jieba 程式在記錄這些斷法的時候多記錄了斷法的機率值,所以最高機率值的斷法,就是利用字典比對所得出的斷詞結果。
11. 再來,Jieba 會將字典比對的斷詞結果中出現的連續單字詞進行組合,然後使用 HMM 隱馬可夫模型來計算新詞的組成。隱馬可夫模型其實是由馬可夫模型所延伸過來的。我們知道馬可夫模型是由狀態機率及狀態轉移機率所組成,隱馬可夫模型跟馬可夫模型不同的地方就在於隱這個字,馬可夫模型的狀態是可以直接觀察到的,而隱馬可夫模型的狀態是無法直接觀察到的,我們只能從其他的可觀測資料來猜出實際的狀態可能長什麼樣子。
12. 隱馬可夫模型是由馬可夫模型延伸過來的,所以先來看一下什麼是馬可夫模型。基本上馬可夫模型的概念就是選定一個狀態作為起點,然後沿著邊隨意走訪任何一個狀態,一直走一直走,沿途累積機率,走累了就停在某狀態。舉例來說,猜天氣就可以使用到馬可夫模型,我們如果知道今天是雨天機率,也知道雨天跟晴天之間的轉移機率,那就可以猜猜看明天也是雨天或晴天的機率。
13. 這邊我用一個實際的例子來說明,有一名旅客,三天後想到台南遊玩,由氣象報告得知今天的降雨機率為 0.2,也知道晴天雨天的轉移機率如下,則此遊客三天後到台南遇到下雨的機率為多少?(解釋投影片)
14. 同樣的,我們用猜天氣的例子來舉例說明隱馬可夫模型,比如現在有個人是瞎子,他無法直接觀察到天氣情況,但他可以察覺到人們在各種天氣中所進行的活動,比如有人在走動、有人在購物、地上是否潮濕等,如果已經累積到足夠的資料量可以知道晴天時有多少機率有人在走動、在購物、地上是否潮濕,雨天時有多少機率有人在走動、在購物、地上是否潮濕,然後也知道雨天跟晴天之間的狀態轉移機率,最後我們看了瞎子記錄的最新五天的可觀察狀態,我們要試著去推算這五天是晴天或雨天,並算出一個最佳的組合。
15. 隱馬可夫模型幾個重要的名詞我們再整理一下,我們有講到隱藏狀態,每個隱藏狀態會有他的初始機率值,在這個例子中的隱藏狀態就是晴天跟雨天。然後隱藏狀態之間會有轉移機率值,在今天是雨天的情況下,明天是雨天的機率是多少,今天是晴天的情況下,明天是雨天的機率是多少,用一個矩陣把所有轉移機率值記下來,然後隱馬可夫模型會有可觀察狀態,每個隱藏狀態都會有若干個可觀察狀態,然後我們可以在隱藏裝態中觀察到各個可觀察狀態的機率值,在這個例子中的可觀察狀態,就是有沒有人在走動或購物或是地上有沒有濕。
16. 好,從瞎子記錄的最新五天的可觀察狀態,我們要試著去推算這五天是晴天或雨天,並算出一個最佳的組合,它的其中一個組合路徑的算法公式大概就長這樣子。這樣直接看公式會覺得很抽象,我們可以直接代入例子來了解這個公式(解釋公式)假設瞎子記錄的這五天可觀察狀態都是人有在外面走動,那其中一個組合就是五天都是晴天,我們去計算這個組合的機率值。(解釋公式)所以我們就讓程式去把每一個組合的機率值都算出來,得到的最大值結果就可能是最符合真實的組合。
17. 把剛才的猜天氣例子舉一反三轉換到斷詞這個問題,斷詞其實就是我們要去猜字在句子中組合的結構,字在句子的結構可分成四種結構,我們稱為 BMES,B代表開頭,M代表中間,E代表結尾、S代表獨立成詞,而我們要去猜字是屬於這四種結構的哪一種,所以結構就是隱藏狀態,而我們可以看到字的序列,所以字的序列本身就是可觀察狀態。套到剛才猜天氣的計算公式,我們將每種結構的排列組合都計算出一個機率值,最大的機率值結果,其實就是最佳的斷詞結果。比如:「即將來臨時」可能就會算出 BEBES 這個排列組合會得到最大的機率值。(看原始碼幫助理解)
18. 了解了 Jieba 的核心演算法之後,我們來看一下究竟要怎麼使用 Jieba 這個斷詞程式
19. 我這邊要先跟各位說明一下,要使用 Jieba 斷詞程式最好還是用 Unix Base 相關的作業系統,比如:Ubuntu 或 Mac,比較不會遇到 Unicode 相關問題,而且安裝環境也會比較方便,大家可以看這張投影片所提供的連結找到符合自己作業系統如何安裝 Python。
20. 而當你照著文章的步驟裝好了 Python,你同時也會安裝好了 pip 這個 Python 的套件管理工具。pip 可以讓你很方便的安裝其他開發者所提供的第三方套件,如果你沒有使用 pip 來管理其他開發者所提供的套件,就需要自己手動去抓這些套件回來,有些比較複雜的套件,可能會與其他的套件有相依關係,這時你就要自己去處理這些問題。如果你是使用 pip 這個管理工具來安裝套件,他如果偵測到目前要裝的套件跟其他套件有相依關係,就會自動幫你處理好,所以最好都使用 pip 來安裝管理第三方套件。使用別人的套件也是一種設計模式,它讓我們不用重新製造輪子,當別人有寫好的套件,我們可以直接使用,然後專注于我們自己的專案開發,這就叫做 Dry(Don’t Repeat Yourself)。
21. 裝好 Python 環境及 pip 之後,我們要先裝一下 Virtualenv 這個套件。這個套件可以讓我們在開發 Python 相關程式的時候可以創造一個分開且完全乾淨不會互相干擾的 Python 環境。相關指令如下:(說明投影片),我們可以來實際看一下,就會比較知道什麼叫分開的 Python 虛擬環境(開終端機)
22. ...
23. 那我們實際來使用一下 Jieba 的斷詞,這是我寫好的一個 Sample Code,斷詞模式是使用預設的精確斷詞模式,我們想要斷詞的句子是「颱風天就是要泛舟啊不然要幹嘛」及「先拆坐墊,公道價八萬一,你是在大聲什麼啦」,程式的語法就是使用 jieba.cut 來進行斷詞(解釋原始碼),我們來執行程式看一下結果。(開終端機)
24. 好,這就是我們剛剛執行程式的結果,感覺結果還不錯。
25. Jieba 還有提供另一個斷詞模式,叫做全模式,我們只要加上一個參數 cut_all,然後設成 True,就可以切換成全模式。全模式的斷詞結果會將所有可以成詞的部份都列出來。我們可以來實際執行一下看有沒有什麼不一樣的地方。(開終端機)
26. 好,這就是我們剛剛執行的結果,上面是精確模式,下面是全模式,大家應該可以很清楚的比較出不同,精確模式就是演算法得出的最精確斷詞結果。而全模式會把所有在句子中可以成為一個詞的詞都列出來。一般來說我們都會是使用上面的精確模式來斷詞,但有時,例如在做搜尋功能的時候,可能就會使用到全模式。
27. Jieba 還有一個功能可以列出斷詞結果在句子中的位置,語法就像這樣(解釋原始碼),jieba.tokenize,這邊要特別注意字串的前面要加一個 u 字,統一將字串都轉成 unicode 來處理。我們來執行程式實際看一下結果。(開終端機)
28. 結果就像這樣,從 0 斷到第 2 個字,以此類推。
29. Jieba 也有標注斷詞詞性的功能,語法就像這樣,使用 pseg.cut 來進行斷詞,得到斷詞詞性的結果。我們來執行程式實際看一下結果。(開終端機)
30. 左邊就是斷詞結果,右邊就是斷詞的詞性,我們要去對一下詞性的列表,才可以知道這些符號的意義。以上就是 Jieba 這個斷詞程式大概的使用方法及功能。
31. 接下來我們用一些實際的例子來看看 Jieba 的斷詞效果。因為我的公司主要是做音樂相關的資料,所以這邊就用歌詞分析來看看 Jieba 的斷詞效果。這裡我們用回聲樂團的座右銘這首歌來進行斷詞。投影片上就是這首歌的歌詞,也就是我們要進行斷詞的文本。
32. 這是歌詞斷詞的 Sample Code(解釋原始碼),我們在這邊沒有切換詞庫,直接使用預設的詞庫,我們來執行程式看一下結果。(開終端機)
33. 其實如果我們使用預設詞庫,我們會發現斷詞的結果很不理想(解釋投影片)
34. 我們再整理一下剛才的斷詞結果,「座右銘」被斷成了「座 / 右銘」,「墓誌銘」被斷成了「墓誌 / 銘」,主要是因為預設詞庫是簡體中文,因此這樣的斷詞結果大部分是使用 HMM 的演算法猜測出來的,所以也相對不準確。使用足夠的詞庫來進行斷詞會得到比較精確的斷詞結果。
35. 好,那就讓我們切換到繁體詞庫試試看,這是 Sample Code(解釋原始碼),我們來執行程式看一下結果。(開終端機)
36. 其實如果我們使用繁體詞庫,我們會發現斷詞的結果很變理想了(解釋投影片)
37. 我們再整理一下剛才的斷詞結果,「座右銘」成功斷成「座右銘」, 「墓誌銘」也成功斷成「墓誌銘」了,所以只要有足夠的詞庫,加上 HMM 的演算法,就可以得到不錯的斷詞結果。
38. Jieba 還有一個功能,它可以算出文章中的關鍵字,語法就像這樣(解釋原始碼),我們來執行程式看一下結果。(開終端機)
39. 這就是 Jieba 算出來文章中的關鍵字,(解釋投影片)
40. 那 Jieba 究竟是怎麼算出文章的關鍵字的呢?其實他背後的演算法就是使用 TF-IDF 這個演算法,這個演算法的核心概念就是「某個詞在一篇文章中出現的頻率高,且在其他文章中很少出現,則此詞語為具代表性的關鍵詞」,(解釋公式),我們也可以從這個演算法知道,為何說斷詞會是文本分析的基礎,因為斷詞之後,我們才可以計算詞頻,進一步發展出更多的演算法。
41. 從剛剛的例子,我們已經多少了解 Jieba 斷詞程式的斷詞效果了,那我們可以再提高斷詞的準確性嗎?大致上可以再做調整的方式有幾個,一個是調整文本資料,如 HMM 模型中的觀察機率及轉移機率,但這需要搜集大量的資料,並整理分析才能完成。或者是我們可以再去調整斷詞的演算法,目前也有很多人繼續研究斷詞的演算法,可能可以增加斷詞的效率,或是增加斷詞的效果。另外一個比較快的方式就是使用自定義詞典,直接用較大的字典來增加斷詞的效果。目前 Jieba 就有 API 可以讓研究者使用自定義詞典來增進斷詞的效果。
42. 這邊就來跟大家說明一下 Jieba 使用自定義詞典的方法,語法就是 jieba.load_userdict,這樣就可以了。需要注意一下自定義詞典的格式,我們來看一下(看原始碼)
43. 除了事先定義好自訂義字典,jieba 也提供了一個可以在程式中動態增加字詞的方法,語法就像這樣(解釋原始碼),我們可以實際來使用看看(Live Demo)(全台大停電)
44. 剛剛我們用 Jieba 來實際看看國語歌詞的斷詞效果,現在如果是台語歌詞,不知道斷詞結果會如何,我們這邊就用滅火器的島嶼天光這首歌來試試看
45. 好,這是 Sample Code(解釋原始碼),我們來執行程式看一下結果。(開終端機)
46. 其實斷詞的結果還算不錯,有些明顯是台語用法的詞才會有斷詞效果不好的問題(解釋投影片)
47. 我們再整理一下剛才的斷詞結果,「「袂當」斷成了「袂」「當」, 「袂記」斷成了「袂」「記」, 「袂有」斷成了「袂」「有」,這都是明顯的台語用詞,所以 jieba 目前無法處理,快速的解法就是使用自定義詞典。
48. 這是使用自定義詞典的 Sample Code(解釋原始碼),我們來執行程式看一下結果。(開終端機)
49. 如此斷詞的效果就變得更好了(解釋投影片)
50. 所以從剛剛的結果來看,我們使用了自定義詞典之後,斷詞結果可以符合我們預期,這是因為我在自定義詞典裡加了這幾個台語用詞(解釋投影片)
51. 以上就是我跟大家分享的 jieba 相關內容,我們可以再延伸一下斷詞的應用,大家可以思考看看這樣的斷詞程式可以用在什麼樣的地方,想想自己可以做出什麼樣的應用。比如我們公司是做音樂的,我們就可以用在歌詞分析,或者是分析歌詞自動建立情境歌單,或者是為創作者做一個自動填詞的功能,或者是做一些相似歌詞推薦的功能。大家可以思考看看斷詞可以讓大家做出什麼樣有趣的應用。
52. 由於 Jieba 是個 Open Source 的 Project,因此有許多人把 Jieba 翻譯成各種程式語言的版本,大家如果不熟悉 Python,也可以找找有沒有自己熟悉的程式語言的版本。像我也蠻熟 PHP 的,因此我將 Jieba 翻譯成了 PHP 的版本,歡迎大家一起加入開發來讓它變得更好!