iT邦幫忙

2022 iThome 鐵人賽

DAY 10
1
AI & Data

文理組人都能上手的入門 NLP(自然語言處理)系列 第 11

[Day 10] 時間都去哪了?資料前處理:成為聽懂人話的社畜之第一步-斷詞斷句(中)

  • 分享至 

  • xImage
  •  

  嗨大家!昨天簡單介紹了斷詞對NLP的重要性,也示範了怎麼用NLTK對英文文本進行段詞跟統整。雖然NLTK提供多種不同語言的服務,當中也包含中文,但它終究是以英文為主的套件。NLTK實際操作起來跟針對中文文本設計的斷詞套件還是有點差距,所以今天會介紹兩個針對中文設計的斷詞器給大家。

Jieba

  jieba是一款由中國人設計的斷詞器,所以當初用來搭建模型的語料使用的都是簡體中文。即使如此,因為他支援繁體中文的關係,還是有很多人在處理繁中語料的時候會選擇它。話不多說就直接開始吧。首先當然就是要安裝一下套件再把它引進來。

!pip install jieba
import jieba

  jieba提供4種模式的斷詞,分別是:

  1. 精確模式
  2. 全模式
  3. 搜索引擎模式
  4. Paddle模式

  因為差異比較細微,他們適合使用的時機也不太一樣,所以今天就只示範最普遍被使用到的精確模式。如果對其他模式有興趣的話可以看官方給的說明嘗試看看他們之間的不同。接下來一樣從最簡單的斷詞開始:

sentence = "今天天氣真好。"
result = jieba.lcut(sentence, cut_all = False)
result

  函式裡面的第一個參數要放目標字串,第二個參數則是用來在精確模式跟全模式之間做選擇的東西。True代表全模式,而False代表精確模式。

# 輸出
['今天', '天氣', '真好', '。']

  我們可以看到運用lcut()斷詞以後,回傳的是一個串列。因為句子簡單,基本上他沒遇到什麼大問題。但是到時候我們處理資料裡面的句子才不會這麼簡單咧。就再拿一篇新聞來測試他好了。

news = "小智研發創辦人黃謙智今天在紐約分享循環經濟實例,包括在COVID-19疫情嚴峻時以回收塑料及廢棄醫材打造模組化病房,彰顯垃圾可救人命,台灣有實力成為創新樞紐。第77屆聯合國大會期間,黃謙智出席紐約非營利組織Concordia年度峰會,在「台灣創新:引領科技進步邁向更永續的未來」場次中,分享台灣材料再生科技公司小智研發17年來運用創新技術落實永續發展的心得。黃謙智出場前,數位發展部長唐鳳透過預錄影片致詞強調,創新科技是解決人類攸關永續共同挑戰的基石。唐鳳提到,總統盃黑客松是公、私團體和國際夥伴協作創新解決方案的重要平台,自2018年舉辦以來,提出「搶救水寶寶」、「健康氣象e起來」等優異創意方案。此外,台灣有許多專注永續發展的企業,致力將回收材料打造成高性能耐久建材的小智研發是其中之一。黃謙智和主持人對談時說,COVID-19(2019冠狀病毒疾病)疫情嚴峻時,符合世界衛生組織(WHO)標準的醫療器材運送困難,小智研發集結創意思維,運用在地資源打造模組化防疫隔離病房,解決病房短缺難題。即使虧錢,這項計畫仍讓人知道垃圾也能拯救人命。"
news_result = jieba.lcut(news, cut_all = False)
news_result
# 輸出
['小智', '研發', '創辦', '人黃謙智', '今天', '在', '紐約', '分享', '循環', '經濟', '實例', ',', '包括', '在', 'COVID', '-', '19', '疫情', '嚴峻', '時以', '回收', '塑料', '及', '廢棄', '醫材', '打造', '模組化', '病房', ',', '彰顯', '垃圾', '可', '救人', '命', ',', '台灣', '有', '實力', '成為', '創新樞紐', '。', '第', '77', '屆', '聯合國', '大會', '期間', ',', '黃', '謙智', '出席', '紐約', '非營利', '組織', 'Concordia', '年度', '峰會', ',', '在', '「', '台灣', '創新', ':', '引領', '科技', '進步', '邁向', '更永續', '的', '未來', '」', '場次', '中', ',', '分享', '台灣', '材料', '再生', '科技', '公司', '小智', '研發', '17', '年來', '運用', '創新', '技術落', '實永續', '發展', '的', '心得', '。', '黃', '謙智', '出場', '前', ',', '數位', '發展', '部長', '唐鳳', '透過', '預錄', '影片', '致詞', '強調', ',', '創新', '科技', '是', '解決', '人類', '攸', '關永續', '共同', '挑戰', '的', '基石', '。', '唐鳳', '提到', ',', '總統', '盃', '黑客', '松是', '公', '、', '私團體', '和', '國際夥伴', '協作創', '新解', '決', '方案', '的', '重要', '平台', ',', '自', '2018', '年', '舉辦', '以來', ',', '提出', '「', '搶救', '水寶寶', '」', '、', '「', '健康', '氣象', 'e', '起來', '」', '等', '優異', '創意', '方案', '。', '此外', ',', '台灣', '有', '許多', '專注', '永續', '發展', '的', '企業', ',', '致力', '將', '回收', '材料', '打', '造成', '高性能', '耐久', '建材', '的', '小智', '研發', '是', '其中', '之一', '。', '黃', '謙智', '和', '主持人', '對', '談時', '說', ',', 'COVID', '-', '19', '(', '2019', '冠狀', '病毒', '疾病', ')', '疫情', '嚴峻', '時', ',', '符合', '世界', '衛生', '組織', '(', 'WHO', ')', '標準', '的', '醫療', '器材', '運送', '困難', ',', '小智研', '發集', '結創', '意思', '維', ',', '運用', '在', '地', '資源', '打造', '模組化', '防疫', '隔離', '病房', ',', '解決', '病房', '短缺', '難題', '。', '即使', '虧錢', ',', '這項', '計畫', '仍', '讓', '人', '知道', '垃圾', '也', '能', '拯救', '人命', '。']

  雖然不像剛剛那麼準確,但結果還算是可以啦。仔細觀察的話會發現,很多斷詞出錯的地方都是專有名詞或比較新的詞彙。像是「總統盃黑克松」、「黃謙智」、「世界衛生組織」跟「2019冠狀病毒疾病」都是jieba無法認出來的專有名詞。如果我們今天就是要把這些東西當作主題來找相關資料,所以已經先知道會常常出現這些字了,有沒有辦法讓他記住這些字來提高斷詞的準確度呢?當然有,我們可以建立新的字典告訴jieba這些東西是一體的。

  因為用jieba建新字典需要從txt檔引進來,所以我們要按照jieba的規定先寫一個包含這些新詞的txt檔。

with open("new_word.txt","w") as f:
        f.write("總統盃黑客松\n黃謙智\n世界衛生組織\n2019冠狀病毒疾病")

  解釋一下上面這段程式碼,以寫出方式(第二個參數)打開名為new_word.txt的檔案(如果不存在的話,python會r建一個新檔案)並把他稱作f。在f裡面寫入括號裡的東西。因為jieba要求每個新詞都要自己佔據一行,所以這邊用代表換行的\n來區隔這些新詞。

jieba.load_userdict("userdict.txt")

  用load_userdict()把我們自己定義的新詞字典讀進來以後,他就會被寫進jieba的字典裡了。接著讓我們看看斷詞結果是不是變得比較精確了~糟糕,突然發現剛剛忘記把「小智研發」跟「COVID-19」也放進去裡面,看來只好用散裝的方式把他們寫進jieba的字典裡了。下面這是把新詞加進jieba字典的另外一種方法,因為一次只能放一個新詞進去,所以比較適合在只有一兩個新詞的時候使用。

jieba.add_word('小智研發')
jieba.add_word('COVID-19')

  如果中途發現加錯東西進去的話,也可以用del_word()把它拿掉,但這邊就不做示範了。

  加入新詞之後不要忘記我們還有停止詞跟礙眼的標點符號要拿掉。因為jieba沒有提供停止詞字典,我這邊用的是Nick Yuu整理的繁中停止詞文檔。拿掉停止詞的方法就跟昨天的一樣,先宣告一個新的空串列,把斷詞結果一個一個拿出來看在不在stopword list裡面,如果不在的話就寫進新串列。

stopword = open("Chinese_stopwords.txt", "r", encoding='UTF-8').read()
stopword_list = stopword.split("\n")
result = jieba.lcut(news, cut_all = False)
clean_result = []
for i in result:
  if i not in stopword_list:
    token = i
    clean_result.append(token)
print(clean_result)
# 輸出
['小智研發', '創辦', '人', '黃謙智', '今天', '紐約', '分享', '循環', '經濟', '實例', '包括', 'COVID-19', '疫情', '嚴峻', '時以', '回收', '塑料', '廢棄', '醫材', '打造', '模組化', '病房', '彰顯', '垃圾', '救人', '命', '台灣', '實力', '成為', '創新樞紐', '77', '屆', '聯合國', '大會', '期間', '黃謙智', '出席', '紐約', '非營利', '組織', 'Concordia', '年度', '峰會', '「', '台灣', '創新', '引領', '科技', '進步', '邁向', '更永續', '未來', '」', '場次', '中', '分享', '台灣', '材料', '再生', '科技', '公司', '小智研發', '17', '年來', '運用', '創新', '技術落', '實永續', '發展', '心得', '黃謙智', '出場', '前', '數位', '發展', '部長', '唐鳳', '透過', '預錄', '影片', '致詞', '強調', '創新', '科技', '解決', '人類', '攸', '關永續', '共同', '挑戰', '基石', '唐鳳', '提到', '總統盃黑客松', '公', '私團體', '國際夥伴', '協作創', '新解', '決', '方案', '重要', '平台', '2018', '年', '舉辦', '以來', '提出', '「', '搶救', '水寶寶', '」', '「', '健康', '氣象', 'e', '」', '優異', '創意', '方案', '台灣', '許多', '專注', '永續', '發展', '企業', '致力', '回收', '材料', '造成', '高性能', '耐久', '建材', '小智研發', '黃謙智', '主持人', '談時', '說', 'COVID-19', '2019冠狀病毒疾病', '疫情', '嚴峻', '時', '符合', '世界衛生組織', 'WHO', '標準', '醫療', '器材', '運送', '困難', '小智研發', '集結創', '意思', '維', '運用', '資源', '打造', '模組化', '防疫', '隔離', '病房', '解決', '病房', '短缺', '難題', '虧錢', '這項', '計畫', '人', '知道', '垃圾', '拯救', '人命']

  我們可以看到經過處理之後的斷詞結果看起來真的比原本理想多了。既然斷完詞也清完資料了,我們當然也要統計一下詞頻。今天要運用的是在python內建的collections套件裡面的Counter()來計算詞頻。使用Counter()統計詞頻後,他會回傳一個字典給我們,而這個字典裡面有一個自動幫我們排序詞頻高低的函式most_common()。直接使用的話可以得到由高到低排列的詞頻串列。如果只想看前幾筆資料的話,可以在裡面輸入數值,像下面這樣。

from collections import Counter
freq = Counter(clean_result)
freq.most_common(3)
# 輸出
[('小智研發', 4), ('黃謙智', 4), ('台灣', 4)]

CkipTagger

  CkipTagger是中研院開發的一套中文處理工具,它可以做的事情包含斷詞(word segmentation)、詞性標註(POS tagging)跟實體辨識(Named Entity Recognition, NER)。都是在語料處理的過程中很重要的東西,但因為今天的主題是斷詞,我們就只先看斷詞怎麼操作,之後講到詞性標註的時候會再示範怎麼使用。

  使用CkipTagger的前置作業比較搞剛一點,除了安裝它的本體之外,還需要安裝tensorflowgdown

!pip install ckiptagger
!pip install tensorflow
!pip install gdown

  安裝完畢之後要讓它把模型下載到我們現在所在的工作資料夾裡面,所以要加上下面這段程式碼:

from ckiptagger import data_utils
data_utils.download_data_gdown("./")

  下載完畢就可以正式開始。因為今天要做的是斷詞,所以先把斷詞工具引進來就好。引進來之後要讓它從模型裡面把斷詞器拿出來。

from ckiptagger import WS
ws = WS("./data")

  好了之後就可以正式進行斷詞了~

ckip_result = ws([news])
print(ckip_result)

  來看看什麼都不做的時候,它的結果會不會比jieba好呢。

# 輸出
[['小智', '研發', '創辦人', '黃謙智', '今天', '在', '紐約', '分享', '循環', '經濟', '實例', ',', '包括', '在', 'COVID-19', '疫情', '嚴峻', '時', '以', '回收', '塑料', '及', '廢棄', '醫材', '打造', '模組化', '病房', ',', '彰顯', '垃圾', '可', '救', '人命', ',', '台灣', '有', '實力', '成為', '創新', '樞紐', '。', '第77', '屆', '聯合國', '大會', '期間', ',', '黃謙智', '出席', '紐約', '非', '營利', '組織', 'Concordia', '年度', '峰會', ',', '在', '「', '台灣', '創新', ':', '引領', '科技', '進步', '邁向', '更', '永續', '的', '未來', '」', '場次', '中', ',', '分享', '台灣', '材料', '再生', '科技', '公司', '小智', '研發', '17', '年', '來', '運用', '創新', '技術', '落實', '永續', '發展', '的', '心得', '。', '黃謙智', '出場', '前', ',', '數位', '發展部長', '唐鳳', '透過', '預錄', '影片', '致詞', '強調', ',', '創新', '科技', '是', '解決', '人類', '攸關', '永續', '共同', '挑戰', '的', '基石', '。', '唐鳳', '提到', ',', '總統盃', '黑客松', '是', '公', '、', '私', '團體', '和', '國際', '夥伴', '協作', '創新', '解決', '方案', '的', '重要', '平台', ',', '自', '2018年', '舉辦', '以來', ',', '提出', '「', '搶救', '水寶寶', '」', '、', '「', '健康', '氣象', 'e', '起來', '」', '等', '優異', '創意', '方案', '。', '此外', ',', '台灣', '有', '許多', '專注', '永續', '發展', '的', '企業', ',', '致力', '將', '回收', '材料', '打造成', '高性能', '耐久', '建材', '的', '小智', '研發', '是', '其中', '之', '一', '。', '黃謙智', '和', '主持人', '對談', '時', '說', ',', 'COVID-19', '(', '2019', '冠狀', '病毒', '疾病', ')', '疫情', '嚴峻', '時', ',', '符合', '世界', '衛生', '組織', '(', 'WHO', ')', '標準', '的', '醫療', '器材', '運送', '困難', ',', '小智', '研發', '集結', '創意', '思維', ',', '運用', '在地', '資源', '打造', '模組化', '防疫', '隔離', '病房', ',', '解決', '病房', '短缺', '難題', '。', '即使', '虧錢', ',', '這', '項', '計畫', '仍', '讓', '人', '知道', '垃圾', '也', '能', '拯救', '人命', '。']]

  喔喔喔喔!看起來ckiptagger對專有名詞的辨識力比jieba還要高,「黃謙智」跟「COVID-19」都被順利斷出來,而且「總統盃」跟「黑客松」各自都是完整的。個人感覺ckiptagger的結果比較理想一點。不過還好他有沒找出來的新詞,不然我就沒辦法示範怎麼加新詞進去字典裡面了XDD

from ckiptagger import construct_dictionary
add_words = {
    "世界衛生組織": 1,
    "2019冠狀病毒疾病": 1,
    "小智研發": 1,
}
dictionary = construct_dictionary(add_words)

  ckiptagger增加新詞的方式是先用字典把這些詞跟我們希望它所佔的權重存起來。接下來再在斷詞的時候加入第二個參數。你可以視情況選擇要指定這個字典為「推薦字典」還是「強制字典」。也就是說我們要不要硬性規定它只要遇到這個東西就一定要這樣斷開。當然你也可以各有一本,但我們這邊只是簡單示範,所以就先指定為強制字典。

ckip_new_result = ws(
    [news],
    #recommend_dictionary = dictionary #推薦字典
    coerce_dictionary = dictionary #強制字典
)
ckip_clean_result = []
for i in ckip_new_result[0]:
    if i not in stopword_list:
        token = i
        ckip_clean_result.append(token)
print(ckip_clean_result)
['小智研發', '創辦人', '黃謙智', '今天', '紐約', '分享', '循環', '經濟', '實例', '包括', 'COVID-19', '疫情', '嚴峻', '時', '回收', '塑料', '廢棄', '醫材', '打造', '模組化', '病房', '彰顯', '垃圾', '救', '人命', '台灣', '實力', '成為', '創新', '樞紐', '第77', '屆', '聯合國', '大會', '期間', '黃謙智', '出席', '紐約', '非', '營利', '組織', 'Concordia', '年度', '峰會', '「', '台灣', '創新', '引領', '科技', '進步', '邁向', '永續', '未來', '」', '場次', '中', '分享', '台灣', '材料', '再生', '科技', '公司', '小智研發', '17', '年', '運用', '創新', '技術', '落實', '永續', '發展', '心得', '黃謙智', '出場', '前', '數位', '發展部長', '唐鳳', '透過', '預錄', '影片', '致詞', '強調', '創新', '科技', '解決', '人類', '攸關', '永續', '共同', '挑戰', '基石', '唐鳳', '提到', '總統盃', '黑客松', '公', '私', '團體', '國際', '夥伴', '協作', '創新', '解決', '方案', '重要', '平台', '2018年', '舉辦', '以來', '提出', '「', '搶救', '水寶寶', '」', '「', '健康', '氣象', 'e', '」', '優異', '創意', '方案', '台灣', '許多', '專注', '永續', '發展', '企業', '致力', '回收', '材料', '打造成', '高性能', '耐久', '建材', '小智研發', '黃謙智', '主持人', '對談', '時', '說', 'COVID-19', '2019冠狀病毒疾病', '疫情', '嚴峻', '時', '符合', '世界衛生組織', 'WHO', '標準', '醫療', '器材', '運送', '困難', '小智研發', '集結', '創意', '思維', '運用', '在地', '資源', '打造', '模組化', '防疫', '隔離', '病房', '解決', '病房', '短缺', '難題', '虧錢', '項', '計畫', '人', '知道', '垃圾', '拯救', '人命']

  比較一下兩個斷詞器的結果可以發現有一些細微的差異,因為新聞文本算是兩岸語言使用差距比較小的文體,所以能做到這樣,但其他文體就不一定了。其實如果去看ckiptaggergithub頁面就會發現,他們提到自己的斷詞效果已經超越jieba。但是真的是這樣嗎?答案就留給大家嘗試用不同文體測試看看去尋找囉。有一點可以確定的是,ckiptagger的動作非常緩慢,如果你很趕時間的話可能選jieba比較理想,不過我不能保證品質就是了。

  本來還要示範怎麼製作酷炫的文字雲炫耀給朋友看的,但是真的打太多東西了TT我晚一點會再多發一篇上來,有興趣的人可以點進去看看~沒有興趣的人應該就是明天見了!


參考資料

Jieba 官方
CkipTagger 官方


上一篇
[Day 9] 時間都去哪了?資料前處理:成為聽懂人話的社畜之第一步-斷詞斷句(英)
下一篇
[Day 11] 時間都去哪了?資料前處理:聽懂進階人話的關鍵-詞性標註
系列文
文理組人都能上手的入門 NLP(自然語言處理)31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言