雖然章節標題用的是詞彙網絡,但我們其實關注的是詞彙之間的關係。前面我們談了最常出現的詞、最重要的詞彙,這個章節則要拉高一個維度,換一個方法看事情。
共現分析(co-occurence analysis),也就是研究兩個或多個事件同時出現的模式(pattern)的分析方法。在文字探勘中,通常都是用來研究單個詞彙(或特殊用法)在同一篇文章或句子中出現的頻率。
當我們將共現分析應用於大量文本時,就能建立起一個完整的「文字網絡」。在這個網絡中,節點(node)代表單詞,而邊(edge)則代表它們之間的共現關係。這種網絡能夠揭示文本中隱藏的語義結構和關聯性。舉例來說,我們可以看到有人談起台灣會強調民主,有人談到台灣則更強調經濟,大約就是這樣的一種概念。
共現關係有幾個好處,包含能夠找到肉眼看不出暗藏的關係,顯示哪些單詞經常一起出現,還能顯示它們是如何相互關聯、強度有多高,這種資訊對對理解文本中的隱含意義非常有價值;它還能夠幫助我們視覺化文本結構和主題,用圖表呈現,例如先用傳統的套件igrpah
或者tidyverse宇宙底下的tidygraph
處理資料,接著用件igrpah
或者tidyverse宇宙底下的ggraph
繪製圖表。
最後,就是剛剛提到的優勢,從單維的指標,近一步往上拉城多維度的分析方式。不再只有考慮單詞本身。
有不同方法可以查看詞彙關係,前面在分詞中提過的 bigram 就是其中一個。「厲害」比不上「好厲害」的稱讚程度,還能夠找到「氣候」連接「變化」這種複合詞彙,因此是一個常用的指標。
我們前面都還是一樣跑斷詞。
library(tidytext)
library(tidyverse)
library(jiebaR)
library(lubridate)
df_speech_clean <- read_csv("data/df_speech_clean.csv")
df_speech_pre <-
df_speech_clean %>%
mutate(text = str_to_lower(text)) %>%
mutate(text = str_remove_all(text, " |\\n|\\r|\\t")) %>%
mutate(text = str_replace_all(text, "台灣", "臺灣")) #%>%
df_stop <- read_table("data/停用詞-繁體中文.txt", col_names = F) %>% rename(stopword = 1)
### segment
cutter <- worker("tag", stop_word = "data/停用詞-繁體中文.txt")
vector_word <- c("中華民國", "李登輝", "蔣中正", "蔣經國", "李登輝", "陳水扁", "馬英九")
new_user_word(cutter, words = vector_word)
## [1] TRUE
### text part
df_speech_seg <-
df_speech_pre %>%
mutate(text = str_replace_all(text, "台灣|臺灣", "臺灣")) %>%
mutate(text = str_remove_all(text, "\\n|\\r|\\t|:| | ")) %>%
mutate(text = str_remove_all(text, "[a-zA-Z0-9]+")) %>%
mutate(text_segment = purrr::map(text, function(x)segment(x, cutter))) %>%
mutate(text_POS = purrr::map(text_segment, function(x)names(x))) %>%
unnest(c(text_segment, text_POS)) %>%
select(-text, everything(), text) %>%
anti_join(df_stop, by = c("text_segment" = "stopword"))
斷完詞後,這邊開始出現變化!首先,我們按照年份分組,將資料切分成一年一年的演講稿。為什麼呢?因為我們想看兩個東西,一個是整體的詞彙 bigram,一個是分年的詞彙 bigram。
df_segment_split <- df_speech_seg %>%
mutate(year = year(date)) %>%
select(year, text_segment) %>%
rename(text = text_segment) %>%
group_split(year)
第一部分我們先不管年,想看整體的詞彙 bigram。
###計算bigram
#計算collocation前先清掉標點符號
df_segment_split_clean <- df_segment_split %>%
map( ~ filter(.,!str_detect(text, ",|。|?|!|,|\\?|!|、|;|;|:|「|」")) ) %>%
map( ~ filter(.,!str_detect(text, " ")) ) %>%
map( ~ filter(.,text != "") ) %>%
map( ~ mutate(., text2 = lead(text))) %>%
map( ~ filter(., !is.na(text))) %>%
map( ~ filter(., !is.na(text2))) %>%
map( ~count(., text, text2)) %>% bind_rows() %>%
group_by(text, text2) %>%
summarise(n = sum(n)) %>%
ungroup()
這邊就是整體的詞彙 bigram。
df_segment_split_clean %>% arrange(desc(n)) %>% head(10)
## # A tibble: 10 × 3
## text text2 n
## <chr> <chr> <int>
## 1 國際 社會 53
## 2 臺灣 經濟 34
## 3 國人 同胞 31
## 4 經濟 發展 23
## 5 國家 安全 21
## 6 今天 中華民國 20
## 7 副 總統 20
## 8 經濟 合作 20
## 9 兩千 三百萬 19
## 10 這塊 土地 19
接下來則分年看,看每年有沒有什麼差!
df_segment_split_year <- df_segment_split %>%
map( ~ filter(.,!str_detect(text, ",|。|?|!|,|\\?|!|、|;|;|:|「|」")) ) %>%
map( ~ filter(.,!str_detect(text, " ")) ) %>%
map( ~ filter(.,text != "") ) %>%
map( ~ mutate(., text2 = lead(text))) %>%
map( ~ filter(., !is.na(text))) %>%
map( ~ filter(., !is.na(text2))) %>%
map( ~count(., year, text, text2)) %>% bind_rows() %>%
group_by(year, text, text2) %>%
summarise(n = sum(n)) %>%
ungroup()
df_segment_split_year %>% group_by(year) %>%
arrange(year, desc(n)) %>%
mutate(rank = row_number()) %>%
filter(rank <= 3) %>%
mutate(text3 = str_c(text, "-", text2)) %>%
ungroup() %>%
select(year, text3, rank) %>%
pivot_wider(names_from = rank, values_from = text3) %>%
tail(10)
## # A tibble: 10 × 4
## year `1` `2` `3`
## <dbl> <chr> <chr> <chr>
## 1 2011 先進-同胞 辛亥-雙十 紀念-辛亥
## 2 2012 民主-法治 今年-月 主權-漁權
## 3 2013 公民-社會 自由-經濟 經濟-島
## 4 2014 民主-憲政 中國-大陸 新-住民
## 5 2015 九二-共識 副-總統 兩岸-和平
## 6 2016 幾個-月 過去-幾個 做出-貢獻
## 7 2017 新-南向 更好-臺灣 兌現-承諾
## 8 2018 國家-安全 基礎-建設 投資-環境
## 9 2019 三年-多來 壯大-臺灣 這塊-土地
## 10 2020 這段-時間 供應鏈-重組 區域-和平