在進行中文 Text Mining 前處理時,必須先經過斷詞處理。社群當中存在相當好的斷詞處理工具,如 jieba。但斷詞時常遇到一個問題:文本中重要的詞彙因為不常見於其它地方而被斷開,像是人物角色名稱。要處理這個問題,需將自訂詞庫提供給斷詞套件,才不會將重要詞彙斷開。

這邊將使用 jiebaR,介紹使用自訂詞庫的斷詞方式,並提供自訂詞庫的製作方式。

示範語料

這裡使用金庸神雕俠侶第三十二回 — 情是何物作為斷詞的文本。武俠小說在此是個很好的例子,因為裡面有許多人物名稱和專有名詞。

因為著作權問題1,語料的原始檔(032.txt)將不會出現在本文的 GitHub repo 中。

製作自訂詞庫

取得小說這類文本的角色名稱與特殊名詞乍看之下可能非常耗工耗時,但有些時候其實相當容易,尤其是著名的小說。這要歸功於維基百科,因為越是著名的小說,其越有可能有詳盡的維基百科頁面,而維基百科對製作詞庫最重要的特色在於其頁面的超連結,因為通常只有專有名詞才會成為一個維基頁面上的超連結

這邊使用維基百科的神鵰俠侶角色列表作為詞庫的來源。以下使用rvest套件清理此頁面:

library(rvest)
library(dplyr)
library(magrittr)
library(knitr)

path <- "神鵰俠侶角色列表.html" 
# 這裡已先行下載網頁,若無可直接使用網址

data <- read_html(path) %>% 
    html_nodes("ul") %>% html_nodes("li") %>%
    html_nodes("a") %>% html_text()

觀察頁面後,可發現多數與小說相關的詞彙都位在 unordered list 下的連結內文(<a> tag),因此透過 3 個html_nodes()取得連結,並用html_text()擷取連結內文。

接著看看擷取的詞彙,可以發現這些詞彙依照順序大致可區分成三個來源:

  1. 自維基頁面的目錄擷取之連結
  2. 內文的連結(這是我們要的)
  3. 其它連結
    • 對應至頁面最下方,與小說有關但並非小說主要內容的連結,如,「射雕英雄传角色列表」。另外,也包含維基百科頁面的固定連結,如「編輯」、「討論」、「下載為PDF」等。
data <- unique(data)

data[1:3]
[1] "1 主角"           "2 桃花島"         "2.1 「北丐」門派"
data[21:25]
[1] "楊過"       "射鵰英雄傳" "楊康"       "穆念慈"     "全真教"    
data[207:211]
[1] "射雕英雄传角色列表" "倚天屠龙记角色列表" "查"                
[4] "论"                 "编"                

我們要的內容介在data[21](楊過)至data[206](樊一翁)之間。此外,亦可手動加入連結中沒有的詞彙:

data <- as_data_frame(data[21:206]) %>% 
    rbind("過兒", "靖哥哥") # 手動額外輸入

head(data, 4) %>% kable("markdown", align="c")
value
楊過
射鵰英雄傳
楊康
穆念慈

最後,將data存成.csv檔,方便未來使用:

readr::write_csv(data, "sdxl_wordlist.csv")

jiebaR 斷詞

準備好自訂詞庫後,要開始對文本進行斷詞。

jiebaR 斷詞可以選擇外來檔案或將檔案讀入後在進行斷詞,這邊將文本檔案讀入再斷詞:

library(stringr)
raw_text <- readr::read_file("032.txt")

raw_text %>% str_trunc(80)
[1] "第三十二回 情是何物\r\n\r\n  當黃蓉、一燈、郭芙等被困大廳之時,楊過和小龍女正在花前並肩共語。不久程英和陸無雙到來。小龍女見程英溫雅靦腆,甚是投緣,拉住..."

無自訂詞庫

首先,我們可以看看沒有自訂詞庫的斷詞效果:

library(jiebaR)
stop_words <- readr::read_table2("stop-zh-tw-withpunc",
                                 col_names = F) %>%
                     rbind("\n", "\r") %>%
                     set_names("word")

seg <- worker(bylines = F, symbol = T)

segment(raw_text, seg) %>%
    as_data_frame() %>% 
    anti_join(stop_words, by=c("value"="word")) %>%
    count(value) %>%
    arrange(desc(n)) %>%
    head() %>% kable("markdown", align="c")
value n
156
小龍女 115
91
公孫止 86
楊過 76
65

可以看到有些斷詞是正確的,如「公孫止」。但某些似乎常常斷錯,例如,「黃蓉」、「楊過」(某些似乎斷錯,導致有許多單獨的「楊」)。

使用自訂詞庫

jiebaR::worker()中設定自訂詞庫的位置:user = "sdxl_wordlist.csv",即可在斷詞系統中新增字典:

seg <- worker(bylines = F, symbol = T,
              user = "sdxl_wordlist.csv")

segment(raw_text, seg) %>%
    as_data_frame() %>% 
    anti_join(stop_words, by=c("value"="word")) %>%
    count(value) %>%
    arrange(desc(n)) %>%
    head() %>% kable("markdown", align="c")
value n
楊過 187
150
小龍女 119
公孫止 104
黃蓉 95
李莫愁 59

可以看到使用自訂詞庫後,斷詞變得有意義多了。


  1. 本文目的僅在促進教育與學術,並無營利企圖。且本文僅顯示極少的小說內容,應屬合理使用。若有侵犯著作權的疑慮,麻煩透過 Email 與我聯絡。