--- GA: UA-159972578-2 --- ###### tags: `R` `Data Processing` `資料前處理` `Regex` `正則表達式` `文字分析` `Text Mining` `情緒分析` `Sentiment Analysis` # Sympsons(Chinese)_Sentiment Analysis Reference: [Text Mining Ebook](https://www.tidytextmining.com) 看code完整執行結果: [Rpubs Ver.](https://rpubs.com/RitaTang/588732) # Data介紹 + Data Source: [辛普森一家 字幕庫](http://m.proxypy.org/p?q=bG10aC40NjgwNS9zYnVzL2FsLnVrdW1pei53d3cvLzpwdHRo%0A) + 第31季第12集~第16集(共5集) + 中英皆有(此例用的是中文繁體字幕) ## 斷詞系統 + Jieba(結巴) ## 情緒字典 + 中文: LIWC(本例使用) # 文本探索 ## 系統參數設定 ```{r} Sys.setlocale(category = "LC_ALL", locale = "zh_TW.UTF-8") # 避免中文亂碼 ``` ## 讀取資料 ```{r warning=FALSE, message=FALSE, cache=FALSE, error=FALSE} pacman::p_load(tidytext, jiebaR, tidyverse, stringr, wordcloud2, wordcloud, scales, reshape2) simps <- read_file("./s31.txt") simps_e <- read_file("./s31_e.txt") simps = gsub("[0-9]+", "", simps) # 字幕檔會有太多時間戳記 ``` ## 文字前處理 ### 初始化斷詞引擎 ```{r} # 直接下worker()即可,這裡則使用自訂字典和停用字 jieba_tokenizer = worker(user="./user_dict.txt", stop_word = "./stop_words.txt") ``` ### 查看斷詞結果 ```{r} # 法1 segment(simps, jieba_tokenizer) # 法2 jieba_tokenizer <= simps # 法3 jieba_tokenizer[simps] ``` ### 動態新增自訂詞彙/停用字 動態新增詞彙一定要先做才能做動態停用字(因為一旦存成一個變數,new_user_word就無法再塞進新變數的jieba_tokenizer) ```{r} new_user_word(jieba_tokenizer, c("下一個", "驚嘆", "馬姬")) # 新增詞彙 tokens = segment(simps, jieba_tokenizer) tokens %>% head(100) simps = filter_segment(tokens, c("晚上好", "這周", "正", "成", "一個", "再")) # 篩除停用字 segment(simps, jieba_tokenizer) %>% head(100) ``` ### 新增集數欄位 ```{r} simps_ep = data.frame(word = simps[nchar(simps)>1], stringsAsFactors = FALSE) %>% mutate(episode = (11+cumsum(str_detect(word, regex("^第.*集$"))))) # .比對任何一個字元(換行不算) # *比對前一個字元零次或更多次 ``` ### 文字雲視覺化 ```{r} tokens_count = simps_ep %>% group_by(word) %>% summarise(count = n()) %>% filter(count > 10) %>% arrange(desc(count)) head(tokens_count, 10) js_color_fun = "function (word, weight) { return (weight > 30) ? '#f02222' : '#c09292'; }" tokens_count %>% wordcloud2(color = htmlwidgets::JS(js_color_fun), backgroundColor = "black") ``` ![](https://i.imgur.com/FEUWwzJ.png) 可以發現即使是繁體字幕,仍有一些簡體字未轉成功 # 情緒分析 ## 準備字典 ```{r} p = read_file("./liwc/positive.txt") n = read_file("./liwc/negative.txt") positive = data.frame(word = strsplit(p, "[,]")[[1]], sentiment = "positive", stringsAsFactors = FALSE) negative = data.frame(word = strsplit(n, "[,]")[[1]], sentiment = "negative", stringsAsFactors = FALSE) LIWC_ch = rbind(positive, negative) LIWC_ch %>% head(10) ``` ## 以LIWC字典判斷辛普森一家台詞的情緒傾向 ```{r} simps_ep %>% select(word) %>% inner_join(LIWC_ch) %>% group_by(sentiment) %>% summarise(cnt = n()) ``` ## 分析每集情緒 ```{r} plot_table = simps_ep %>% group_by(episode, word) %>% summarise(count = n()) %>% arrange(desc(count)) %>% inner_join(LIWC_ch) %>% group_by(episode, sentiment) %>% summarise(cnt = sum(count)) plot_table %>% ggplot() + geom_line(aes(x=episode, y=cnt, colour=sentiment)) + ggtitle("每集情緒差異") + theme(text=element_text(family="蘋方-繁 中黑體", size=12), plot.title=element_text(hjust = 0.5)) ``` ![](https://i.imgur.com/l6FK7or.png) + 基本上皆為正面>負面,與我們平時認知的辛普森家庭稍微有些不同,我解釋原因為: + 辛普森雖然給人帶有嘲諷的印象,但是畢竟還是喜劇,光從詞彙意義上來判斷,很容易被歸類為正面用語 + 字典定義影響,例如:在恐怖電影/遊戲產業專用的字典裡,「恐怖」、「嚇人」就不算負面用字,而是符合需求的正面詞彙。 + 第13集中,正面與負面差距最大,可能是五集中最歡樂的一集 + 第14集中,正面與負面差距最小,是較為中性的一集 ## 分析第13集中的正負面詞彙 ```{r} simps_ep %>% group_by(episode, word) %>% summarise(count = n()) %>% filter(episode==13) %>% inner_join(LIWC_ch) %>% group_by(word, sentiment) %>% summarise(count=sum(count)) %>% filter(count > 1) %>% # 只有1次的太多了因此濾掉 acast(word ~ sentiment, value.var = "count", fill = 0) %>% comparison.cloud(colors = c("gray80", "gray20"), max.words = 100, family = "蘋方-繁 中黑體") ``` ![](https://i.imgur.com/TsbiO6t.png)