批踢踢韓國瑜聲量分析

文章推薦指數: 80 %
投票人數:10人

透過中山管院文字分析平台在批踢踢的HatePolitics看板,搜尋關鍵字:[韓國瑜、韓國 ... A.F4B.html WER0930 ## 2 https://www.ptt.cc/bbs/HatePolitics/M.1556044230. 批踢踢韓國瑜聲量分析 讀書會第二組徐湛、張傳銘、李沂倩、郭睿紘、林益祥、徐建德 系統設置 #Sys.setlocale(category="LC_ALL",locale="zh_TW.UTF-8")#Forubuntu Sys.setlocale("LC_CTYPE","cht")#Forwindows. ##[1]"Chinese(Traditional)_Taiwan.950" 安裝需要的packages packages=c("readr","tm","data.table","dplyr","stringr","tidyverse","jiebaR","tidytext","ggplot2","tidyr","topicmodels","LDAvis","webshot","purrr","ramify","RColorBrewer","wordcloud2","htmlwidgets","servr","scales") existing=as.character(installed.packages()[,1]) for(pkginpackages[!(packages%in%existing)])install.packages(pkg) library(pacman) require(readr) require(tm) require(data.table) require(dplyr) require(stringr) require(jiebaR) require(udpipe) require(tidytext) require(ggplot2) require(tidyr) require(topicmodels) require(LDAvis) require(wordcloud2) require(webshot) require(htmlwidgets) require(servr) require(purrr) require(ramify) require(RColorBrewer) mycolors%as.Date("%Y/%m/%d") 資料描述 2019年4月23日,高雄市市長韓國瑜宣布參選2020總統大選。

透過中山管院文字分析平台在批踢踢的HatePolitics看板,搜尋關鍵字:[韓國瑜、韓國魚、霸韓、韓導、韓總],時間從2019-04-23~2020-04-22,為期一年的資料,總篇數為23735篇。

資料預覽 fish_hatePolitics%>% mutate(year=year(artDate),month=month(artDate))%>% group_by(year,month)%>% summarise(count=n())%>% ggplot(aes(x=month,y=count))+ geom_bar(stat="identity")+ facet_grid(~year) 1.可以觀察到資料主要分佈去年5-6月以及12月,今年討論聲量則明顯下降。

2.【聲量高點原因推測】(1)2019年5-6月:韓國瑜剛宣布要參選總統,引發諸如“烙跑市長”、“選上總統,高雄上班”等議題。

(2)2020年12月:鄰近一月中的總統大選,正值“競選活動”與“總統辯論會”的高峰期。

Tokenization 初始化斷詞引擎,並加入停用字 jieba_tokenizer=worker(stop_word="stop_words.txt") jieba_tokenizer1){ tokens1] return(tokens) } }) } 過濾特殊字元 tokens% mutate(id=c(1:nrow(fish_hatePolitics)))%>% unnest_tokens(word,sentence,token=fish_tokenizer)%>% filter(!str_detect(word,regex("[0-9a-zA-Z]"))) 把名稱統一 tokens$word[which(tokens$word==c("韓國魚","韓董","韓導","韓總"))]="韓國瑜" ##Warningintokens$word==c("韓國魚","韓董","韓導","韓總"):較長的物件長度並 ##非較短物件長度的倍數 tokens$word[which(tokens$word=="郭董")]="郭台銘" tokens$word[which(tokens$word==c("柯p","柯P"))]="柯文哲" ##Warningintokens$word==c("柯p","柯P"):較長的物件長度並非較短物件長度的倍數 tokens$word[which(tokens$word=="小英")]="蔡英文" 查看前20筆資料 tokens%>%head(20) ##artTitleartDateartTime ##1[討論]還以為韓總是聰明人2019-04-2310:24:28 ##2[討論]還以為韓總是聰明人2019-04-2310:24:28 ##3[討論]還以為韓總是聰明人2019-04-2310:24:28 ##4[討論]還以為韓總是聰明人2019-04-2310:24:28 ##5[討論]還以為韓總是聰明人2019-04-2310:24:28 ##6[討論]還以為韓總是聰明人2019-04-2310:24:28 ##7[討論]還以為韓總是聰明人2019-04-2310:24:28 ##8[討論]還以為韓總是聰明人2019-04-2310:24:28 ##9[討論]還以為韓總是聰明人2019-04-2310:24:28 ##10[討論]還以為韓總是聰明人2019-04-2310:24:28 ##11[討論]還以為韓總是聰明人2019-04-2310:24:28 ##12[討論]還以為韓總是聰明人2019-04-2310:24:28 ##13[討論]還以為韓總是聰明人2019-04-2310:24:28 ##14[討論]還以為韓總是聰明人2019-04-2310:24:28 ##15[討論]還以為韓總是聰明人2019-04-2310:24:28 ##16[討論]還以為韓總是聰明人2019-04-2310:24:28 ##17[討論]還以為韓總是聰明人2019-04-2310:24:28 ##18[討論]還以為韓總是聰明人2019-04-2310:24:28 ##19[討論]還以為韓總是聰明人2019-04-2310:24:28 ##20[討論]還以為韓總是聰明人2019-04-2310:24:28 ##artUrlartPoster ##1https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##2https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##3https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##4https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##5https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##6https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##7https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##8https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##9https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##10https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##11https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##12https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##13https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##14https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##15https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##16https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##17https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##18https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##19https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##20https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.htmlWER0930 ##artCatcommentNumpushbooidword ##1HatePolitics841831以為 ##2HatePolitics841831韓國瑜 ##3HatePolitics841831兵法 ##4HatePolitics841831高雄 ##5HatePolitics841831這局 ##6HatePolitics841831棋中 ##7HatePolitics841831力挽狂瀾 ##8HatePolitics841831我本 ##9HatePolitics841831認為 ##10HatePolitics841831要選 ##11HatePolitics841831總統 ##12HatePolitics841831意思 ##13HatePolitics841831最好 ##14HatePolitics841831時機 ##15HatePolitics841831屁股 ##16HatePolitics841831還沒 ##17HatePolitics841831坐熱 ##18HatePolitics841831豈不是 ##19HatePolitics841831朱立倫 ##20HatePolitics841831前車之鑑 詞頻 計算所有字在“單一文集”中的總詞頻 word_count% group_by(id,artTitle,artDate,word)%>% summarise(count=n())%>% ungroup() 計算所有字在“所有文集”中的總詞頻 tokens_count% group_by(word)%>% summarise(count=sum(count))%>% arrange(desc(count)) tokens%>% count(word,sort=TRUE)%>% top_n(10)%>% mutate(word=reorder(word,n))%>% ggplot(aes(word,n))+ geom_col()+ xlab(NULL)+ ylab("出現次數")+ coord_flip() ##Selectingbyn 詞頻文字雲 wordcloud2(tokens_count,size=1) 分析總統大選前後討論內容的差異 總統大選前文字雲 word_count%>% filter(artDate==as.Date('2020-01-11'))%>% select(word,count)%>% group_by(word)%>% summarise(count=sum(count))%>% filter(count>20)%>%#過濾出現太少次的字 wordcloud2() wordcloud 總統大選後文字雲 word_count%>% filter(artDate==as.Date('2020-01-13'))%>% select(word,count)%>% group_by(word)%>% summarise(count=sum(count))%>% filter(count>20)%>%#過濾出現太少次的字 wordcloud2() wordcloud 一月十一日總統大選後,“罷免”字眼成為熱門 罷免聲量 word_count%>% filter(word=="罷免"|word=="下台"|word=="罷韓"|word=="光復高雄")%>% ggplot(aes(x=artDate,y=count))+ geom_bar(stat="identity")+ scale_x_date(date_breaks="1month",date_labels="%m/%d") “罷免”達到巔峰的十個日子 word_count%>% filter(word=="罷免"|word=="下台"|word=="罷韓"|word=="光復高雄")%>% group_by(artDate=artDate)%>% summarise(count=sum(count))%>% arrange(desc(count))%>% slice(1:10) ###Atibble:10x2 ##artDatecount ## ##12020-04-08110 ##22020-01-1391 ##32019-12-2289 ##42020-01-1189 ##52019-12-2184 ##62020-01-3074 ##72020-01-1472 ##82019-09-1370 ##92019-12-1169 ##102019-06-2765 2020年04月:韓國瑜遞狀聲請停止執行罷免案、提出普篩制度、提出海軍官兵若拒絕疫調將開罰2020年01月:總統大選2019年12月:總統大選辯論會、韓國瑜上博恩夜夜秀、wecare大遊行2019年09月:韓國瑜否定“挖石油”言論、郭台銘退出國民黨2019年06月:韓國瑜請假表公開、學生當面嗆韓 草包聲量 word_count%>% filter(word=="草包")%>% ggplot(aes(x=artDate,y=count))+ geom_bar(stat="identity")+ scale_x_date(date_breaks="1month",date_labels="%m/%d") “草包”達到巔峰的十個日子 word_count%>% filter(word=="草包")%>% group_by(artDate)%>% summarise(count=sum(count))%>% arrange(desc(count))%>% slice(1:10) ###Atibble:10x2 ##artDatecount ## ##12019-05-1335 ##22019-12-0133 ##32019-05-0331 ##42019-05-0631 ##52019-05-0428 ##62019-05-1727 ##72019-05-0726 ##82020-01-1122 ##92019-08-2921 ##102019-12-0321 2019年05月:草包之歌流傳2019年12月:總統大選辯論會、韓國瑜上博恩夜夜秀、wecare大遊行2020年01月:總統大選2019年08月:晶晶體風波 情緒分析 準備LIWC字典 全名LinguisticInquiryandWordCounts,由心理學家Pennebaker於2001出版 以LIWC字典判斷文集中的word屬於正面字還是負面字 #正向字典txt檔 #以,將字分隔 P% inner_join(LIWC)%>% arrange(desc(count))%>% mutate(word=factor(word,levels=rev(unique(word))))%>% group_by(sentiment)%>% top_n(n=10,wt=count)%>% ungroup()%>% ggplot(aes(word,count,fill=sentiment))+ geom_col(show.legend=TRUE)+ labs(x=NULL,y="詞頻")+ facet_wrap(~sentiment,ncol=2,scales="free")+ coord_flip()#轉置 ##Joining,by="word" 以LIWC情緒字典分析 統計每天的文章正面字的次數與負面字的次數 sentiment_count% select(artDate,word,count)%>% inner_join(LIWC)%>% group_by(artDate,sentiment)%>% summarise(count=sum(count)) ##Joining,by="word" 過去一年的情緒起伏 sentiment_count%>% ggplot()+ geom_line(aes(x=artDate,y=count,colour=sentiment))+ scale_x_date(date_labels="%m/%d") 1月11日總統大選後,情緒起伏 sentiment_count%>% ggplot()+ geom_line(aes(x=artDate,y=count,colour=sentiment))+ scale_x_date(date_labels="%m/%d",limits=as.Date(c("2020-01-01","2020-03-01")))+ geom_vline(aes(xintercept=as.numeric(artDate[which(sentiment_count$artDate==as.Date('2020/01/11'))[1]])),colour="black",linetype="dashed",alpha=.3) ##Warning:Removed572row(s)containingmissingvalues(geom_path). 將資料轉換為DocumentTermMatrix(DTM) tokens_dtm% count(artUrl,word)%>% rename(count=n) fish_dtm% cast_dtm(artUrl,word,count) fish_dtm ##<> ##Non-/sparseentries:1317797/2620355363 ##Sparsity:100% ##Maximaltermlength:14 ##Weighting:termfrequency(tf) inspect(fish_dtm[1:10,1:10])#查看前十筆資料 ##<> ##Non-/sparseentries:12/88 ##Sparsity:88% ##Maximaltermlength:4 ##Weighting:termfrequency(tf) ##Sample: ##Terms ##Docs九二共識人物 ##https://www.ptt.cc/bbs/HatePolitics/M.1555068495.A.5D0.html11 ##https://www.ptt.cc/bbs/HatePolitics/M.1555128913.A.636.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1555477358.A.A83.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1556047007.A.BD2.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1556049755.A.D99.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1556050417.A.5C3.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1556051849.A.913.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1556053627.A.B8B.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1556057390.A.908.html00 ##Terms ##Docs力量土包子不好 ##https://www.ptt.cc/bbs/HatePolitics/M.1555068495.A.5D0.html231 ##https://www.ptt.cc/bbs/HatePolitics/M.1555128913.A.636.html000 ##https://www.ptt.cc/bbs/HatePolitics/M.1555477358.A.A83.html000 ##https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.html000 ##https://www.ptt.cc/bbs/HatePolitics/M.1556047007.A.BD2.html000 ##https://www.ptt.cc/bbs/HatePolitics/M.1556049755.A.D99.html000 ##https://www.ptt.cc/bbs/HatePolitics/M.1556050417.A.5C3.html000 ##https://www.ptt.cc/bbs/HatePolitics/M.1556051849.A.913.html000 ##https://www.ptt.cc/bbs/HatePolitics/M.1556053627.A.B8B.html000 ##https://www.ptt.cc/bbs/HatePolitics/M.1556057390.A.908.html000 ##Terms ##Docs中心內容分享 ##https://www.ptt.cc/bbs/HatePolitics/M.1555068495.A.5D0.html211 ##https://www.ptt.cc/bbs/HatePolitics/M.1555128913.A.636.html000 ##https://www.ptt.cc/bbs/HatePolitics/M.1555477358.A.A83.html000 ##https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.html000 ##https://www.ptt.cc/bbs/HatePolitics/M.1556047007.A.BD2.html000 ##https://www.ptt.cc/bbs/HatePolitics/M.1556049755.A.D99.html010 ##https://www.ptt.cc/bbs/HatePolitics/M.1556050417.A.5C3.html000 ##https://www.ptt.cc/bbs/HatePolitics/M.1556051849.A.913.html000 ##https://www.ptt.cc/bbs/HatePolitics/M.1556053627.A.B8B.html000 ##https://www.ptt.cc/bbs/HatePolitics/M.1556057390.A.908.html010 ##Terms ##Docs午宴心得 ##https://www.ptt.cc/bbs/HatePolitics/M.1555068495.A.5D0.html11 ##https://www.ptt.cc/bbs/HatePolitics/M.1555128913.A.636.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1555477358.A.A83.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1556044230.A.F4B.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1556047007.A.BD2.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1556049755.A.D99.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1556050417.A.5C3.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1556051849.A.913.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1556053627.A.B8B.html00 ##https://www.ptt.cc/bbs/HatePolitics/M.1556057390.A.908.html00 查看DTM矩陣,可以發現是個稀疏矩陣。

建立LDA模型 fish_lda ##11九二共識0.000114 ##22九二共識0.000170 ##31人物0.000654 ##42人物0.000865 ##51力量0.000645 ##62力量0.000120 ##71土包子0.0000430 ##82土包子0.0000439 ##91不好0.000474 ##102不好0.000774 ###...with220,902morerows 從topics中可以得到特定主題生成特定詞彙的概率。

尋找Topic的代表字 top_terms% group_by(topic)%>% top_n(10,beta)%>% ungroup()%>% arrange(topic,-beta) top_terms%>% mutate(topic=as.factor(topic), term=reorder_within(term,beta,topic))%>% ggplot(aes(term,beta,fill=topic))+ geom_col(show.legend=FALSE)+ facet_wrap(~topic,scales="free")+ coord_flip()+ scale_x_reordered() 尋找兩個主題差異最大的詞彙 topics%>% mutate(topic=paste0("topic",topic))%>%#根據主題名稱重新命名欄位 spread(topic,beta)%>% filter(topic1>.001|topic2>.001)%>% mutate(log_ratio=log2(topic2/topic1))%>% filter(abs(log_ratio)>3.95)%>% mutate(term=reorder(term,log_ratio))%>%#依據log_ratio值(主題類別)排序詞項 ggplot(aes(log_ratio,term))+ geom_col(show.legend=FALSE) 1.上圖中,左側為主題一,右側為主題二。

2.透過上方的兩張圖,感覺兩個主題看起來差不多,沒有明顯的差異,嘗試看看分多一點topics。

更多主題 嘗試2,5,10,15,25主題數,將結果存起來,再做進一步分析 #ldas=c() #topics=c(2,5,10,15,25) #for(topicintopics){ #start_time% ggplot(aes(k,perplex))+ geom_point()+ geom_line()+ labs(title="EvaluatingLDAtopicmodels", subtitle="Optimalnumberoftopics(smallerisbetter)", x="Numberoftopics", y="Perplexity") ##Warning:`data_frame()`isdeprecated,use`tibble()`. ##Thiswarningisdisplayedoncepersession. perplexity越小越好,但是太小的話,主題數會分太細。

通常會找一個主題數適當,且perplexity比較低的主題。

因此,在後續分析時,本組將分為“10個”主題。

LDA後續分析 根據前面的探索之後,我們對於資料有更加了解,並且看完每個主題數的LDAvis之後,選定主題數10的結果來作後續的分析查看各個主題的單詞組成比率 fish_lda=ldas[[3]]##選定topic為10的結果 topics ##11九二共識1.18e-24 ##22九二共識1.31e-15 ##33九二共識3.86e-14 ##44九二共識2.93e-30 ##55九二共識4.98e-24 ##66九二共識2.04e-21 ##77九二共識6.24e-19 ##88九二共識1.37e-16 ##99九二共識5.17e-29 ##1010九二共識1.29e-3 ###...with1,104,550morerows 每一行代表一個主題中的一個詞彙 尋找Topic的代表字 整理出每一個Topic中生成概率最高的10個詞彙。

#取出每一個Topic中生成概率最高(beta值最高)的10個詞彙 top_terms% group_by(topic)%>% top_n(10,beta)%>% ungroup()%>% arrange(topic,-beta) #繪製長條圖 top_terms%>% mutate(topic=as.factor(topic), term=reorder_within(term,beta,topic))%>% ggplot(aes(term,beta,fill=topic))+ geom_col(show.legend=FALSE)+ facet_wrap(~topic,scales="free")+ coord_flip()+ scale_x_reordered() 可以看到topic都被一開始所使用的搜尋關鍵字影響看不出每一群的差異。

移除常出現、跨主題共享的詞彙。

remove_word=c("韓國瑜","高雄","總統","市長","韓粉","國民黨","韓導","韓總","一定","完全","比較","還要","表示","新聞","記者","去年","問題") top_terms% filter(!term%in%remove_word)%>% group_by(topic)%>% top_n(10,beta)%>% ungroup()%>% arrange(topic,-beta) top_terms%>% mutate(topic=as.factor(topic), term=reorder_within(term,beta,topic))%>% ggplot(aes(term,beta,fill=topic))+ geom_col(show.legend=FALSE)+ facet_wrap(~topic,scales="free")+ coord_flip()+ scale_x_reordered() 可以看出每個主題主要在討論什麼了! 主題命名 topic_name=c('造勢活動','韓國瑜V.S.郭台銘','民調:韓V.S.蔡、郭、柯','議會質詢','直播狂熱粉','防疫議題','罷韓議題','黨內大佬立場','網軍黑韓','國際局勢') Document主題分佈 #foreverydocumentwehaveaprobabilitydistributionofitscontainedtopics tmResult% arrange(desc(`民調:韓V.S.蔡、郭、柯`))%>% head(10) 可以看到“民調:韓V.S.蔡、郭、柯”這個主題主要涵蓋了“韓、蔡、郭、柯的各式民調變動”。

了解主題在時間的變化 fish_topic[,c(11:20)]=sapply(fish_topic[,c(11:20)],as.numeric) fish_topic%>% group_by(artDate=format(artDate,"%Y%m"))%>% summarise_if(is.double,sum,na.rm=TRUE)%>% melt(id.vars="artDate")%>% ggplot(aes(x=artDate,y=value,fill=variable))+ geom_bar(stat="identity")+ylab("value")+ scale_fill_manual(values=mycolors)+ theme(axis.text.x=element_text(angle=90,hjust=1)) 由於我們在今年2月-4月的資料太少,所以將這三個月去除。

去除筆數少月份 fish_topic%>% group_by(artDate=format(artDate,"%Y%m"))%>% filter(artDate<202002)%>% summarise_if(is.double,sum,na.rm=TRUE)%>% melt(id.vars="artDate")%>% ggplot(aes(x=artDate,y=value,fill=variable))+ geom_bar(stat="identity")+ylab("value")+ scale_fill_manual(values=mycolors)+ theme(axis.text.x=element_text(angle=90,hjust=1)) 可以看出每個月的聲量,但是不能很清楚出每個月的比例 以比例了解主題時間變化 fish_topic%>% group_by(artDate=format(artDate,"%Y%m"))%>% filter(artDate<202002)%>% summarise_if(is.double,sum,na.rm=TRUE)%>% melt(id.vars="artDate")%>% group_by(artDate)%>% mutate(total_value=sum(value))%>% ggplot(aes(x=artDate,y=value/total_value,fill=variable))+ geom_bar(stat="identity")+ylab("proportion")+ scale_fill_manual(values=mycolors)+ theme(axis.text.x=element_text(angle=90,hjust=1)) 現在我們可以看到每個月主題的佔比了!



請為這篇文章評分?