iT邦幫忙

2021 iThome 鐵人賽

DAY 2
2
自我挑戰組

30天初步了解自然語言處理-自學筆記系列 第 2

[Day2] 斷詞介紹

一. 為何需要斷詞
最主要的原因就是中文的最小一個單位就是一個詞,通常不能直接餵一個句子給你的語言模型處理,這樣模型連詞跟詞的關係都不知道,所以我們需要先利用斷詞,讓電腦了解這個詞與哪些詞會很長相連,那些詞又是無關的,例如: '很'是個副詞麻,他後面基本上只會接形成詞或動詞對吧,像是'漂亮'、'帥氣'這類的詞。但在不同語言上都會有不同的斷詞方法,像是中文與英文,英文也是需要斷詞,但他們的詞語詞之間就是用空白相隔,與中文比較起來,英文算是比較好斷開的,那中文就需要用一些統計的方法來處理拉。

二. 斷詞的演算法
目前斷詞的演算法大致如下:

  • 基於詞典的分詞法:照一定的策略將待匹配的字符串和一個已建立好的詞典中的詞進行匹配,通常會採用雙向匹配的方法,但這方法的能力有限,例如像是新發明的詞就無法進行匹配,但這方法在最一開始做中文斷詞是真的滿有用的,比起順向匹配、逆向匹配,雙向匹配的準確度是滿高的
  • 統計的機器學習算法:如HMM,CRF (Conditional Random Field),這類方法應該算是目前的大宗吧,Jieba(一個斷詞的套件)對於不存在於字典的字詞就是用統計的方法來處理的
  • 深度學習的算法:LSTM,深度學習的方法應該算是比較新的,但其實就是處理LSTM多對多的模型,之前有看過有人利用雙向LSTM+CRF實做斷詞,有興趣的可以去找找

我等等下面會以Jieba斷詞為主,故這邊稍微提及一下Jieba的斷詞方法,他會分成2種部份:

  • 針對存在於字典的字詞:
    • step1. 根據字典產生Trie樹 (字典樹)
    • step2. 根據 Trie 樹建立給定輸入句的 DAG(有向無環圖)
    • step3. 使用Dynamic Programming 來找出最大機率路徑,此路徑及為基於詞頻最大的分詞結果
  • 針對不存在於字典的字詞:
    • 使用隱馬可夫模型(HMM) 與維特比演算法(Viterbi) 來進行分詞辨識,找出最合適的組合

三. Jieba
Jieba其實算是中文滿常用的斷詞套件,但他對簡體效果比較好,繁體效果有些差,如果想要針對繁中斷詞的話,滿推薦CKIP的,但我記得斷詞速度是滿慢的,而且因為他是client-server的架構,還滿常發生斷線的問題,本人之前碩論再用CKIP斷詞時很常發生過QQ,最後還是改用jieba了,其他的斷詞套件如Hanlp最近還滿常聽到的,聽說斷詞的準確度還不錯,但本文為以Jieba為主。

  1. 安裝
    總之呢要先安裝套件,對python熟的人,應該都知道就是這樣安裝:
    pip install jieba,然後在自己的python檔引入 import jieba 就可以開始用囉

  2. 載入繁體中文的辭典~這個的位置在Jieba的github有提供,這裡附上網址

    # 載入繁體辭典
    jieba.set_dictionary('dict.txt.big')
    
  3. Jieba的四種斷詞模式:

    • 精確模式: Jieba基礎的斷詞模式,也就是基本款
    text_after_jieba = jieba.cut("我愛自然語言處理", cut_all=False) # 精確模式
    print("精確模式: " + "/ ".join(text_after_jieba))
    # output: 精確模式: 我/ 愛/ 自然語言/ 處理
    
    • 全模式: 將cut_all設為true,這個模式下會將可以斷的詞再繼續斷開,列出所有可能的詞~
    text_after_jieba = jieba.cut("我愛自然語言處理", cut_all=True) # 全模式
    print("全模式: " + "/ ".join(text_after_jieba))
    # output: 全模式: 我/ 愛/ 自然/ 自然語言/ 語言/ 處理
    
    • paddle模式: Jieba導入一個深度學習框架PaddlePaddle來進行分詞,據說是利用GRU,必須要先利用jieba.enable_paddle()來啟動~
    # 啟用paddle模式
    jieba.enable_paddle()
    seg_list = jieba.cut("我愛自然語言處理", use_paddle=True)  # 使用paddle
    print("paddle: " + "/ ".join(seg_list))
    # output: paddle: 我/ 愛/ 自然/ 語言/ 處理
    
    • 搜尋引擎模式: 這個模式跟全模式很像,都可以將詞再更切分
    text_after_jieba = jieba.cut_for_search("我愛自然語言處理")  # 搜尋引擎模式
    print("搜尋引擎: " + "/ ".join(text_after_jieba))
    
    # output: 搜尋引擎: 我/ 愛/ 自然/ 語言/ 處理
    

    以上是Jieba提供的四種斷詞模式,但其實用在簡體效果會較好

  4. 辨識新字詞:

    • 像上述說的,若Jieba遇到新詞,可以透過HMM來預測,如下,這邊容我直接用官網例子QQ,沒試到好的繁中例子:
    words = jieba.cut("他来到了网易杭研大厦", HMM=True) #HMM 設為 True
    words_list = []
    for word in words:
        words_list.append(word)
    
    print(f'HMM output:{words_list}')
    
    # output: HMM output:['他', '来到', '了', '网易', '杭研', '大厦']
    

    這個例子是辨識了'杭研'這個詞,有興趣的可以試一下

  5. 載入自定義辭典:

    • Jieba也提供載入自訂義辭典,例如我建立一個了一個txt,如下:
    韓國瑜
    年終獎金
    
    • 來比較一下載入自定義與沒有自定義的差異,載入自定義的方式用jieba.load_userdict('./dict_define.txt')來載入:
    text = '韓國瑜今天頒發年終獎金'
    words = jieba.cut(text)
    words_list = []
    for word in words:
        words_list.append(word)
    
    print(f'output:{words_list}')
    
    jieba.load_userdict('./dict_define.txt')
    
    words = jieba.cut(text)
    words_list = []
    for word in words:
        words_list.append(word)
    
    print(f'output:{words_list}')
    
    # output:['韓國', '瑜', '今天', '頒發', '年終獎金']
    # output:['韓國瑜', '今天', '頒發', '年終獎金']
    

    jieba也支持透過add_word的function來動態增加辭典唷~

  6. Jieba也支持pos tagging,如下範例:

    import jieba.posseg as pseg
    
    words = jieba.posseg.cut('我愛自然語言處理')
    for word, flag in words:
        print(f'{word} {flag}')
    
    # 我 r
    # 愛 v
    # 自然語言 l
    # 處理 v
    

    在繁體上有些POS感覺不是很適合,如果想知道對應的詞性,可參考這個網站

    其實Jieba還有滿多功能我沒介紹的,有興趣的可以去他們的github看唷~~


這次的篇幅好像不小心拉太長了QQ,明天會說明比較簡單的stemming與lemmatization


上一篇
[Day1] 何謂自然語言處理
下一篇
[Day3] stemming 與 lemmatization
系列文
30天初步了解自然語言處理-自學筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言