截長句成短句,再用 monpa 來斷詞。(2020更新)

Wen-Chao Yeh
17 min readAug 15, 2019

--

MONPA 罔拍是一個提供正體中文斷詞、詞性標註以及命名實體辨識的多任務模型。

自然語言處理常是多種資料分析或是人工智慧相關應用的基底程序,而斷詞又是自然語言處理的基礎工程。語言與使用的社會群體息息相關,簡體中文與正體中文間常用的字詞也有很大差異,因此以簡體中文為基礎語料設計出來的 “Jieba 結巴”斷詞套件運用在正體中文就常有一些袂紲拍的地方。多年來,終於有專為正體中文設計的斷詞、詞性標註以及命名實體辨識的 python 套件釋出,MONPA 罔拍

pip install monpa

就可以完成安裝,使用方便性遠遠超過兩年前的網頁版本。

不過,畢竟是以深度學習訓練出來的模型,語料限制也就有處理文字數目的限制,如果一股腦地將長文直接斷詞,除了超出限定字數的部分會被丟失,甚至沒丟失的部分也可能失了準度。所以說明文件才建議將長文切割成短句再送入 monpa 斷詞。

這裏略舉一例予有需要的開發者參考。

菲力普.普曼 (Philip Pullman) 的黑暗元素三部曲非常適合小孩子,大人們閱讀,不說教卻又富有哲理的奇幻小說,讀完全書會喜悅滿足而不是空空如也。本次改版就用第三部曲『琥珀望遠鏡』威爾與天使的對話來講解分句斷詞。

「那我會做些什麼?」威爾問,但立刻又說:「不,還是別告訴我。我應該決定自己要做的事,如果你說我應該作戰、治療、探險或任何事,我會老掛在心上。如果我最後真做了你說的事,我會很怨恨,覺得毫無選擇,但如果我沒去做,我會覺得愧疚,因為我應該那麼做。不管我要做什麼,我會自己選擇,而不是由別人選擇。」

「你已邁向智慧的第一步了。」賽芬娜爾說。

摘自【THE AMBER SPYGLASS — His Dark Materials Trilogy III】,第三十七章:沙丘

import monpasentence="「那我會做些什麼?」威爾問,但立刻又說:「不,還是別告訴我。我應該決定自己要做的事,如果你說我應該作戰、治療、探險或任何事,我會老掛在心上。如果我最後真做了你說的事,我會很怨恨,覺得毫無選擇,但如果我沒去做,我會覺得愧疚,因為我應該那麼做。不管我要做什麼,我會自己選擇,而不是由別人選擇。」「你已邁向智慧的第一步了。」賽芬娜爾說。摘自【THE AMBER SPYGLASS - His Dark Materials Trilogy III】第三十七章:沙丘"print(f'原句共有 {len(sentence)} 個字元\n')result = monpa.cut(sentence)print(result)

當直接將長度 228 字元的原句 sentence 使用 monpa 的 cut function 斷詞,可以發現最後的斷詞是『Dark Ma』,而後面字元都被丟掉了。

原句共有 228 個字元

['「', '那', '我', '會', '做', '些', '什麼', '?', '」', '威爾', '問', ',', '但', '立刻', '又', '說', ':', '「', '不', ',', '還是', '別', '告訴', '我', '。', '我', '應該', '決定', '自己', '要', '做', '的', '事', ',', '如果', '你', '說', '我', '應該', '作戰', '、', '治療', '、', '探險', '或', '任何', '事', ',', '我', '會', '老', '掛', '在', '心', '上', '。', '如果', '我', '最後', '真', '做', '了', '你', '說', '的', '事', ',', '我', '會', '很', '怨恨', ',', '覺得', '毫無', '選擇', ',', '但', '如果', '我', '沒', '去', '做', ',', '我', '會', '覺得', '愧疚', ',', '因為', '我', '應該', '那麼', '做', '。', '不管', '我', '要', '做', '什麼', ',', '我', '會', '自己', '選擇', ',', '而', '不是', '由', '別人', '選擇', '。', '」', '「', '你', '已', '邁向', '智慧', '的', '第一', '步', '了', '。', '」', '賽芬娜爾', '說', '。', '摘自', '【', 'THE AMBER SPYGLASS - His ', 'Dark Ma']

怎麼辦?

先依需求將長文以『。』或是『,』(這只是舉例,當然可以選擇其他的字元)當作分隔點,切成數個短句再依序使用 monpa 來得到短句的斷詞,最後整合成長句的完整斷詞。譬如,將上面例子以『。』切成短句再處理就可以得到完整斷詞結果。

python 的 split() 可以用來就指定字元分句,例如。

sentence.split("。")

可以得到分句後的 List,但每句的都被丟棄了。

['「那我會做些什麼?」威爾問,但立刻又說:「不,還是別告訴我',
'我應該決定自己要做的事,如果你說我應該作戰、治療、探險或任何事,我會老掛在心上',
'如果我最後真做了你說的事,我會很怨恨,覺得毫無選擇,但如果我沒去做,我會覺得愧疚,因為我應該那麼做',
'不管我要做什麼,我會自己選擇,而不是由別人選擇',
'」「你已邁向智慧的第一步了',
'」賽芬娜爾說',
'摘自【THE AMBER SPYGLASS - His Dark Materials Trilogy III】第三十七章:沙丘']

所以,我們將分句子取出後先補上再送入 monpa 斷詞,濾掉斷詞結果的最後元素就是完整輸出:

sentence="「那我會做些什麼?」威爾問,但立刻又說:「不,還是別告訴我。我應該決定自己要做的事,如果你說我應該作戰、治療、探險或任何事,我會老掛在心上。如果我最後真做了你說的事,我會很怨恨,覺得毫無選擇,但如果我沒去做,我會覺得愧疚,因為我應該那麼做。不管我要做什麼,我會自己選擇,而不是由別人選擇。」「你已邁向智慧的第一步了。」賽芬娜爾說。摘自【THE AMBER SPYGLASS - His Dark Materials Trilogy III】第三十七章:沙丘"seg = []
for item in sentence.split("。"):
if item != "\n": seg.extend(monpa.cut(f'{item}。'))
print(seg[:-1])

完整的斷詞結果。

['「', '那', '我', '會', '做', '些', '什麼', '?', '」', '威爾', '問', ',', '但', '立刻', '又', '說', ':', '「', '不', ',', '還是', '別', '告訴', '我', '。', '我', '應該', '決定', '自己', '要', '做', '的', '事', ',', '如果', '你', '說', '我', '應該', '作戰', '、', '治療', '、', '探險', '或', '任何', '事', ',', '我', '會', '老', '掛', '在', '心', '上', '。', '如果', '我', '最後', '真', '做', '了', '你', '說', '的', '事', ',', '我', '會', '很', '怨恨', ',', '覺得', '毫無', '選擇', ',', '但', '如果', '我', '沒', '去', '做', ',', '我', '會', '覺得', '愧疚', ',', '因為', '我', '應該', '那麼', '做', '。', '不管', '我', '要', '做', '什麼', ',', '我', '會', '自己', '選擇', ',', '而', '不', '是', '由', '別人', '選擇', '。', '」', '「', '你', '已', '邁向', '智慧', '的', '第一', '步', '了', '。', '」', '賽芬娜爾', '說', '。', '摘自', '【', 'THE AMBER SPYGLASS - His ', 'Dark Materials Trilogy III', '】', '第三十七', '章', ':', '沙丘']

可以寫成小功能,方便日常呼叫使用。譬如:

def LongCut(long_sentence, split_char):
seg = []
for item in long_sentence.split(split_char):
if item != "\n": seg.extend(monpa.cut(f'{item}{split_char}'))
return seg[:-1]
def LongPseg(long_sentence, split_char):
seg = []
for item in long_sentence.split(split_char):
if item != "\n": seg.extend(monpa.pseg(f'{item}{split_char}'))
return seg[:-1]

若要得到 POS 資訊,則使用LongPseg小功能,

result = LongPseg(sentence, "。")
print(result)

輸出結果,

[('「', 'PARENTHESISCATEGORY'), ('那', 'Dk'), ('我', 'Nh'), ('會', 'D'), ('做', 'VC'), ('些', 'Dfb'), ('什麼', 'Nep'), ('?', 'QUESTIONCATEGORY'), ('」', 'PARENTHESISCATEGORY'), ('威爾', 'Nb'), ('問', 'VE'), (',', 'COMMACATEGORY'), ('但', 'Cbb'), ('立刻', 'D'), ('又', 'D'), ('說', 'VE'), (':', 'COLONCATEGORY'), ('「', 'PARENTHESISCATEGORY'), ('不', 'D'), (',', 'COMMACATEGORY'), ('還是', 'D'), ('別', 'D'), ('告訴', 'VE'), ('我', 'Nh'), ('。', 'PERIODCATEGORY'), ('我', 'Nh'), ('應該', 'D'), ('決定', 'VE'), ('自己', 'Nh'), ('要', 'D'), ('做', 'VC'), ('的', 'DE'), ('事', 'Na'), (',', 'COMMACATEGORY'), ('如果', 'Cbb'), ('你', 'Nh'), ('說', 'VE'), ('我', 'Nh'), ('應該', 'D'), ('作戰', 'VA'), ('、', 'PAUSECATEGORY'), ('治療', 'Na'), ('、', 'PAUSECATEGORY'), ('探險', 'VA'), ('或', 'Caa'), ('任何', 'Neqa'), ('事', 'Na'), (',', 'COMMACATEGORY'), ('我', 'Nh'), ('會', 'D'), ('老', 'VH'), ('掛', 'VC'), ('在', 'P'), ('心', 'Na'), ('上', 'Ng'), ('。', 'PERIODCATEGORY'), ('如果', 'Cbb'), ('我', 'Nh'), ('最後', 'Nd'), ('真', 'D'), ('做', 'VC'), ('了', 'Di'), ('你', 'Nh'), ('說', 'VE'), ('的', 'DE'), ('事', 'Na'), (',', 'COMMACATEGORY'), ('我', 'Nh'), ('會', 'D'), ('很', 'Dfa'), ('怨恨', 'VK'), (',', 'COMMACATEGORY'), ('覺得', 'VK'), ('毫無', 'D'), ('選擇', 'Na'), (',', 'COMMACATEGORY'), ('但', 'Cbb'), ('如果', 'Cbb'), ('我', 'Nh'), ('沒', 'D'), ('去', 'D'), ('做', 'VC'), (',', 'COMMACATEGORY'), ('我', 'Nh'), ('會', 'D'), ('覺得', 'VK'), ('愧疚', 'VH'), (',', 'COMMACATEGORY'), ('因為', 'Cbb'), ('我', 'Nh'), ('應該', 'D'), ('那麼', 'D'), ('做', 'VC'), ('。', 'PERIODCATEGORY'), ('不管', 'Cbb'), ('我', 'Nh'), ('要', 'D'), ('做', 'VC'), ('什麼', 'Nep'), (',', 'COMMACATEGORY'), ('我', 'Nh'), ('會', 'D'), ('自己', 'Nh'), ('選擇', 'VC'), (',', 'COMMACATEGORY'), ('而', 'Cbb'), ('不', 'D'), ('是', 'SHI'), ('由', 'P'), ('別人', 'Nh'), ('選擇', 'VC'), ('。', 'PERIODCATEGORY'), ('」', 'PARENTHESISCATEGORY'), ('「', 'PARENTHESISCATEGORY'), ('你', 'Nh'), ('已', 'D'), ('邁向', 'VCL'), ('智慧', 'Na'), ('的', 'DE'), ('第一', 'Neu'), ('步', 'Nf'), ('了', 'T'), ('。', 'PERIODCATEGORY'), ('」', 'PARENTHESISCATEGORY'), ('賽芬娜爾', 'PER'), ('說', 'VE'), ('。', 'PERIODCATEGORY'), ('摘自', 'VC'), ('【', 'PARENTHESISCATEGORY'), ('THE AMBER SPYGLASS - His ', 'ORG'), ('Dark Materials Trilogy III', 'FW'), ('】', 'PARENTHESISCATEGORY'), ('第三十七', 'Neu'), ('章', 'Na'), (':', 'COLONCATEGORY'), ('沙丘', 'Nb')]

時間到了 2020 年尾,經過觀察學生開發程式的過程及開發者的回饋,我們決定將分句功能放上 monpa 的套裝程式內,你可以自行開發適合的分句程式或是直接應用 v0.3.2 版的 utils.short_sentence() 輔助程式。

開始使用輔助功能程式前,請先更新到 v0.3.2 版本並載入 monpa 附屬之 utils 功能。

from monpa import utils

這個 short_sentence function是以 , , , 依序為參考斷點的分句功能程式,輸入須為 string 格式,回傳值是 list 格式。設計是先尋找 200 字元內最後一個 "" 為斷點,若無,則改以 "" 為斷點,以此類推。若 200 字元內皆無法找到預設 4 個標點符號為斷點來分句,就直接從 200 字元處分句。簡單範例如下:

sentence='「那我會做些什麼?」威爾問,但立刻又說:「不,還是別告訴我。我應該決定自己要做的事,如果你說我應該作戰、治療、探險或任何事,我會老掛在心上。如果我最後真做了你說的事,我會很怨恨,覺得毫無選擇,但如果我沒去做,我會覺得愧疚,因為我應該那麼做。不管我要做什麼,我會自己選擇,而不是由別人選擇。」「你已邁向智慧的第一步了。」賽芬娜爾說。摘自【THE AMBER SPYGLASS - His Dark Materials Trilogy III】第三十七章:沙丘'sentence_list = utils.short_sentence(sentence)
for item in sentence_list:
print(item)

輸出發現有 228 字元的 sentence 長句,經 utils.short_sentence 以 "。" 為斷點分成兩個短句。

「那我會做些什麼?」威爾問,但立刻又說:「不,還是別告訴我。我應該決定自己要做的事,如果你說我應該作戰、治療、探險或任何事,我會老掛在心上。如果我最後真做了你說的事,我會很怨恨,覺得毫無選擇,但如果我沒去做,我會覺得愧疚,因為我應該那麼做。不管我要做什麼,我會自己選擇,而不是由別人選擇。」「你已邁向智慧的第一步了。」賽芬娜爾說。
摘自【THE AMBER SPYGLASS - His Dark Materials Trilogy III】第三十七章:沙丘

完整的應用範例,

result = []
for item in utils.short_sentence(sentence):
if item:
result.append(monpa.cut(item))

print(result)
=== 輸出結果 ===[['「', '那', '我', '會', '做', '些', '什麼', '?', '」', '威爾', '問', ',', '但', '立刻', '又', '說', ':', '「', '不', ',', '還是', '別', '告訴', '我', '。', '我', '應該', '決定', '自己', '要', '做', '的', '事', ',', '如果', '你', '說', '我', '應該', '作戰', '、', '治療', '、', '探險', '或', '任何', '事', ',', '我', '會', '老', '掛', '在', '心', '上', '。', '如果', '我', '最後', '真', '做', '了', '你', '說', '的', '事', ',', '我', '會', '很', '怨恨', ',', '覺得', '毫無', '選擇', ',', '但', '如果', '我', '沒', '去', '做', ',', '我', '會', '覺得', '愧疚', ',', '因為', '我', '應該', '那麼', '做', '。', '不管', '我', '要', '做', '什麼', ',', '我', '會', '自己', '選擇', ',', '而', '不是', '由', '別人', '選擇', '。', '」', '「', '你', '已', '邁向', '智慧', '的', '第一', '步', '了', '。', '」', '賽芬娜爾', '說', '。'], ['摘自', '【', 'THE AMBER SPYGLASS - His Dark Materials Trilogy III', '】', '第三十七', '章', ':', '沙丘']]

一個長文到底是要從句號或是任何一個字元做為分句斷點都是使用者最清楚也是最能衡量適宜與否,所以 monpa 只是提供一個簡單輔助程式,至於如何彈性運用就留給開發者決定,也歡迎隨時到 monpa github 巡巡看看。

--

--

Wen-Chao Yeh
Wen-Chao Yeh

Written by Wen-Chao Yeh

行動通訊業界工作十多年,曾任系統架構師與產品經理。清華大學資訊系統與應用研究所博士候選人,研究領域包含但不限於 Generative AI, LLM, RAG, Semantic Search, Sentiment Analysis。

No responses yet