中文斷詞

library(jiebaR)
## Loading required package: jiebaRD
mixseg <- worker()
segment(code='今天天氣真好', jiebar = mixseg)
## [1] "今天" "天氣" "真好"
#edit_dict()

詞頻矩陣

library(jiebaR)
#edit_dict()
#USERPATH
mixseg <- worker()
s  <- "大巨蛋案對市府同仁下封口令?柯P否認"
s1 <- "柯P市府近來飽受大巨蛋爭議"

s.vec <- lapply( list(s, s1), function(e) segment(e, jiebar = mixseg)) 


library(tm)
## Loading required package: NLP
s.corpus <- Corpus(VectorSource(s.vec))
s.dtm <- DocumentTermMatrix(s.corpus)
inspect(s.dtm)
## <<DocumentTermMatrix (documents: 2, terms: 11)>>
## Non-/sparse entries: 14/8
## Sparsity           : 36%
## Maximal term length: 3
## Weighting          : term frequency (tf)
## Sample             :
##     Terms
## Docs 下 同仁 否認 大巨蛋 封口令 市府 柯p 案對 爭議 近來
##    1  1    1    1      1      1    1   1    1    0    0
##    2  0    0    0      1      0    1   1    0    1    1
s.tdm <- TermDocumentMatrix(s.corpus)
inspect(s.tdm)
## <<TermDocumentMatrix (terms: 11, documents: 2)>>
## Non-/sparse entries: 14/8
## Sparsity           : 36%
## Maximal term length: 3
## Weighting          : term frequency (tf)
## Sample             :
##         Docs
## Terms    1 2
##   下     1 0
##   同仁   1 0
##   否認   1 0
##   大巨蛋 1 1
##   封口令 1 0
##   市府   1 1
##   柯p    1 1
##   案對   1 0
##   爭議   0 1
##   近來   0 1

利用新聞資料建立詞頻矩陣

library(readxl)
url <- "https://raw.githubusercontent.com/ywchiu/phalanxrtm/master/data/news.xlsx"
destfile <- "news.xlsx"
curl::curl_download(url, destfile)
news <- read_excel(destfile)
#View(news)

library(jiebaR)
mixseg <- worker()
apple.seg <- lapply(news$content, function(e) segment(e, jiebar = mixseg))
s.corpus     <- Corpus(VectorSource(apple.seg))

control.list <- list(wordLengths=c(2,Inf) )
dtm          <- DocumentTermMatrix(s.corpus, control=control.list)
dim(dtm)
## [1]   899 34233
findFreqTerms(dtm, 200,300)
##  [1] "一定"   "今天"   "問題"   "因"     "政府"   "更新"   "目前"  
##  [8] "知道"   "開始"   "之"     "仍"     "你"     "可能"   "大"    
## [15] "或"     "所"     "指出"   "新聞"   "曾"     "能"     "他們"  
## [22] "向"     "媒體"   "男"     "約"     "蘋果"   "11"     "其"    
## [29] "包括"   "名"     "因為"   "於"     "至"     "進行"   "第"    
## [36] "公司"   "把"     "認為"   "個"     "從"     "跟"     "並"    
## [43] "又"     "就是"   "看"     "下"     "發現"   "可以"   "很"    
## [50] "再"     "新"     "何守正" "網友"   "警方"   "可"
findAssocs(dtm, '何守正', 0.7)
## $何守正
##   小嫻   妙禪 健身房   密友 
##   0.96   0.76   0.74   0.73
dtm.remove <- removeSparseTerms(dtm, 0.99)
dim(dtm.remove)
## [1]  899 3260
#dtm.remove$dimnames$Terms

文章距離計算

library(jiebaR)
mixseg <- worker()
s  <- "大巨蛋案對市府同仁下封口令?柯P否認"
s1 <- "柯P市府近來飽受大巨蛋爭議"

s.vec <- lapply( list(s, s1), function(e) segment(e, jiebar = mixseg)) 


library(tm)
s.corpus <- Corpus(VectorSource(s.vec))
s.dtm <- DocumentTermMatrix(s.corpus)
inspect(s.dtm)
## <<DocumentTermMatrix (documents: 2, terms: 11)>>
## Non-/sparse entries: 14/8
## Sparsity           : 36%
## Maximal term length: 3
## Weighting          : term frequency (tf)
## Sample             :
##     Terms
## Docs 下 同仁 否認 大巨蛋 封口令 市府 柯p 案對 爭議 近來
##    1  1    1    1      1      1    1   1    1    0    0
##    2  0    0    0      1      0    1   1    0    1    1
v1 <- c(1,1,1 ,1,1,1,1,1,0,0)
v2 <- c(0,0,0 ,1,0,1,1,0,1,1)
sum(abs(v1 - v2))
## [1] 7
sum((v1 - v2) ^ 2)
## [1] 7
sqrt(sum((v1 - v2) ^ 2))
## [1] 2.645751
#東北季風影響 北部、東北部濕涼有雨

#國慶日東北季風增強,北部及東北部氣溫稍下降,高溫表現上,北部及東半部約26至29度,其他地區約31、32度,由於各地清晨溫度偏涼,中南部應留意日夜溫差較大,早出晚歸的朋友請添加衣物以免受涼;降雨方面,迎風面水氣增加,其中基隆北海岸、宜蘭及大臺北山區為整天有雨的天氣,並有局部大雨發生的機率,北部地區及花、東也有局部短暫雨,建議參加國慶日活動及前往花蓮欣賞國慶煙火的朋友攜帶雨具備用;至於中南部地區仍維持多雲到晴,午後在山區及屏東地區有局部雷陣雨。

# 東北季風 北部 東北部 濕涼 有雨
# 東北季風 北部 東北部 濕涼 有雨  宜蘭 大臺北  中南部 花蓮 國慶煙火

#       東北季風 北部 東北部 濕涼 有雨  宜蘭 大臺北  中南部 花蓮 國慶煙火
# title   1       1     1     1    1     0       0     0     0     0     
# article 1       1     1     1    1     1       1     1     1     1 


library(proxy)
## 
## Attaching package: 'proxy'
## The following objects are masked from 'package:stats':
## 
##     as.dist, dist
## The following object is masked from 'package:base':
## 
##     as.matrix
a <- c(1, 2, 2, 1, 1, 1, 0)
b <- c(1, 2, 2, 1, 1, 2, 1)
proxy::dist(rbind(a, b), method = 'cosine') 
##            a
## b 0.06180581
library(jiebaR)
mixseg <- worker()
apple.seg <- lapply(news$content, function(e) segment(e, jiebar = mixseg))
s.corpus     <- Corpus(VectorSource(apple.seg))
s.corpus <- tm_map(s.corpus, removeNumbers)
## Warning in tm_map.SimpleCorpus(s.corpus, removeNumbers): transformation
## drops documents
s.corpus <- tm_map(s.corpus, removePunctuation)
## Warning in tm_map.SimpleCorpus(s.corpus, removePunctuation): transformation
## drops documents
control.list <- list(wordLengths=c(2,Inf) )
dtm          <- DocumentTermMatrix(s.corpus, control=control.list)
dim(dtm)
## [1]   899 33905
dtm.remove    <- removeSparseTerms(dtm, 0.99)
dim(dtm.remove)
## [1]  899 3164
library(proxy)
dtm.dist <- proxy::dist(as.matrix(dtm.remove), method = "cosine")
dtm.mat <- as.matrix(dtm.dist)


dtm.mat[1:3, 1:3]
##           1         2         3
## 1 0.0000000 0.7025869 0.7880713
## 2 0.7025869 0.0000000 0.6464768
## 3 0.7880713 0.6464768 0.0000000
news$title[6]
## [1] "Fed升息美元走軟 台幣今再升破30元大關"
order(dtm.mat[6,])[1:10]
##  [1]   6 627 805  20 132 753 118 587 666 721
news$title[order(dtm.mat[6,])[1:10]]
##  [1] "Fed升息美元走軟 台幣今再升破30元大關"          
##  [2] "靜候FOMC結論 台幣平盤整理午盤小貶0.5分"        
##  [3] "耶誕購物旺季 遠百寶慶店推滿5千送5百優惠"       
##  [4] "Fed宣布升息1碼 台股早盤大漲逾百點"             
##  [5] "【Fed有鴿味】美元軟了黃金硬了 美股道指創新高"  
##  [6] "哀鳳SLP訂單有風險 外資降評景碩目標價對半砍"    
##  [7] "Fed升息符合預期 經濟學家:大家可過個平安聖誕節"
##  [8] "傳產撐盤 台股漲27點收10470點"                  
##  [9] "巨騰發出獲利預警 將年減75~85%"                 
## [10] "做辛酸?薪水被扣1萬 還要繳水電瓦斯費"
news$title[order(dtm.mat[17,])[1:10]]
##  [1] "小嫻婚變冒毒菇 勾于美人「奉茶」夢魘"                
##  [2] "遭粉絲頁冒名捲「正嫻」口水戰 于美人:跟我真的無關!"
##  [3] "【獨家內幕】太傷!小嫻被分手 何守正當小三面前攤牌"  
##  [4] "小嫻信奉妙禪 關鍵原因與何守正有關!"                
##  [5] "「小嫻不快樂!」 許聖梅:何守正虧欠她"              
##  [6] "小嫻別傻傻被欺負!女律師說「姐寶」就要這樣對付"      
##  [7] "國小女童寫作文 內容竟是「我的變態爸比」"            
##  [8] "​心理師:情傷背後,看不見的需要與脆弱"                
##  [9] "遭霸凌男童被起底疑歧視黑人 母喊冤:我們不是那種人"  
## [10] "砲轟小嫻被酸民攻陷 「何三姑」粉絲頁關了"
idx <- dtm.mat[17, order(dtm.mat[17,]) ] < 0.5

news$title[as.integer(names(which(idx ==TRUE )))]
## [1] "小嫻婚變冒毒菇 勾于美人「奉茶」夢魘"                
## [2] "遭粉絲頁冒名捲「正嫻」口水戰 于美人:跟我真的無關!"
## [3] "【獨家內幕】太傷!小嫻被分手 何守正當小三面前攤牌"  
## [4] "小嫻信奉妙禪 關鍵原因與何守正有關!"
getSimilarArticle <- function(pos, threshold){
  idx <- dtm.mat[pos, order(dtm.mat[pos,]) ] < threshold
  news$title[as.integer(names(which(idx ==TRUE )))]
}
getSimilarArticle(20, 0.6)
## [1] "Fed宣布升息1碼 台股早盤大漲逾百點"             
## [2] "【Fed有鴿味】美元軟了黃金硬了 美股道指創新高"  
## [3] "【Fed告別秀】葉倫談比特幣 以7個字總結"         
## [4] "Fed升息符合預期 經濟學家:大家可過個平安聖誕節"

聚合式分群

dtm.cluster <- hclust(dtm.dist)
plot(dtm.cluster, hang = -0.1)
fit <- cutree(dtm.cluster, k = 30)
#fit
plot(dtm.cluster, hang = -0.1)
rect.hclust(dtm.cluster, k = 30)

news$title[fit == 5]
## [1] "Fed升息美元走軟 台幣今再升破30元大關"                 
## [2] "桃園夫妻貪20元購物金天天假交易 物流士怒嗆:有那麼窮?"
## [3] "靜候FOMC結論 台幣平盤整理午盤小貶0.5分"               
## [4] "做辛酸?薪水被扣1萬 還要繳水電瓦斯費"                 
## [5] "耶誕購物旺季 遠百寶慶店推滿5千送5百優惠"

KMeans 分群

fit <- kmeans(dtm.dist, centers = 30)
news$title[fit$cluster == 15]
##  [1] "天使換來金斯勒 解決二壘漏洞"                          
##  [2] "大眾臉女子買2支iPhone X 都被同事輕鬆解鎖"             
##  [3] "【有片】生死一瞬間 他被雪崩追著跑險遭活埋"            
##  [4] "努涅茲搶手 美東3強都想要"                             
##  [5] "湖人要「球爸」閉嘴 結果又被譙了"                      
##  [6] "性愛片沒拍到臉 他爽快認「就是我沒錯」"                
##  [7] "【咩姊台語】做直銷開公司建人脈 張誌家與前妻吸千萬捲款"
##  [8] "【暖流】罹癌翁「人老了該走就走」  但「腦麻兒怎麼辦」"  
##  [9] "【舌功片】法拉利姊餐車到台中 舌舔美乃滋喊冤醬髒"      
## [10] "​「今天南京大屠殺80年公祭日」邱毅:可悲又可恨啊"        
## [11] "浩鼎案開庭 翁啟惠:美事一樁被誤會"                    
## [12] "小嫻中分手魔咒! 同公司4女星全都婚變"                  
## [13] "謝金晶誇謝金燕容貌變時尚 桃園跨年無緣同台"            
## [14] "【獨家】母餐廳被控少報勞保 林佑星「前員工就是要錢」"  
## [15] "感情冒粉紅泡泡!張棟樑認身邊「有一些人」"              
## [16] "何守正兩個姊姊護航扯婆媳 「他」戳破媽寶特色"          
## [17] "拿假鈔買檳榔 男辯:檳榔西施當時沒說啊!"              
## [18] "【話當年】被拍和她上賓館 何守正掰了阿妹"              
## [19] "小嫻婚變無徵兆 男星嘆:兩人向來出雙入對"              
## [20] "禮讓前車被警拍照驅趕 駕駛怒批結果挨告了"              
## [21] "賣家自寄自收「洗評價」  物流士超商店員崩潰"           
## [22] "政府勸企業加薪 張忠謀:有違自由人力市場規矩"
library(fpc)
nk <- 2:30
set.seed(123)
SW <- sapply(nk, function(k) {
  fit <- kmeans(dtm.dist,centers = k)
  cluster.stats(dtm.dist, fit$cluster)$avg.silwidth
})

plot(nk, SW, type="l", xlab="number of clusers", ylab="average silhouette width")

使用Louvain

library(igraph)
## 
## Attaching package: 'igraph'
## The following objects are masked from 'package:stats':
## 
##     decompose, spectrum
## The following object is masked from 'package:base':
## 
##     union
m <- as.matrix(dtm.dist)
m[1:3,1:3]
##           1         2         3
## 1 0.0000000 0.7025869 0.7880713
## 2 0.7025869 0.0000000 0.6464768
## 3 0.7880713 0.6464768 0.0000000
m2 <- ifelse(m < 0.4, 1, 0)
m2[1:3,1:3]
##   1 2 3
## 1 1 0 0
## 2 0 1 0
## 3 0 0 1
G  <- graph_from_adjacency_matrix(m2)
wc <- cluster_walktrap(G)
modularity(wc)
## [1] 0.3680795
max(membership(wc))
## [1] 565
#table(membership(wc))
news$title[membership(wc)== 2]
##  [1] "【狗仔偷拍】小嫻搬離何守正家租66坪房 月租6萬元"         
##  [2] "許聖梅心疼小嫻被當空氣 爆何守正「有兩個女學員」"        
##  [3] "【動畫解盤】毒菇跳火線譙seafood 小嫻難瘦香菇"           
##  [4] "不捨善良小嫻慘遭婚變 乃哥「命運捉弄人」"                
##  [5] "【獨家】小嫻賣房求子 婆婆竟拒入籍何家"                  
##  [6] "小心!在美結婚台灣沒登記 偷腥照樣能捉姦"                
##  [7] "小嫻離婚導火線 拉何守正信妙禪"                          
##  [8] "小嫻別傻傻被欺負!女律師說「姐寶」就要這樣對付"          
##  [9] "教友小嫻婚姻觸礁 曾之喬談情避不開Seafood"               
## [10] "小嫻守正結婚在台沒登記 想離婚只有兩條路"                
## [11] "胡瓜2個月前耳聞小嫻婚變 震驚之餘好心疼"                 
## [12] "大姑出面護弟!轟小嫻不能生「媽媽是全台最沒有尊嚴的婆婆」"
## [13] "小嫻信奉妙禪 關鍵原因與何守正有關!"                    
## [14] "小嫻何守正想離婚 必須先做這件事!"                      
## [15] "「小嫻不快樂!」 許聖梅:何守正虧欠她"                  
## [16] "【內幕動畫】小嫻婚變何守正姊反擊 不滿媽煮飯侍奉星媳婦"  
## [17] "小嫻多信妙禪? 曾見證「師父帶我跳舞」"                  
## [18] "【話當年】被拍和她上賓館 何守正掰了阿妹"                
## [19] "小嫻婚變無徵兆 男星嘆:兩人向來出雙入對"                
## [20] "【獨家內幕】太傷!小嫻被分手 何守正當小三面前攤牌"      
## [21] "【小嫻離婚】何守正稱沒有遺憾 人妻女星超火「一嘴屁話」"  
## [22] "【小嫻離婚】3大退讓人財兩失 求子花光430萬積蓄"
m3 <- as.matrix(dtm[membership(wc)== 2,])
n <- sort(apply(m3, 2, sum), decreasing = TRUE)[1:20]
n[nchar(names(n)) >= 2 ]
##   小嫻 何守正   離婚   美國   結婚   妙禪 
##    264    180     82     41     40     38

文章分類

apple.subset <- news[news$category %in% c('財經地產', '娛樂', '社會'), ]

dim(apple.subset)
## [1] 357   5
head(apple.subset)
## # A tibble: 6 x 5
##    X__1 category content                                      link   title
##   <dbl> <chr>    <chr>                                        <chr>  <chr>
## 1     2 社會     被控來台涉發展情報組織的中國學生周泓旭,因接觸我方外交部官員而露餡落網,今年9月被台北… https… 陸生共諜…
## 2     5 財經地產 受到Fed升息,及明年升息步伐均符合市場預期影響,國際美元在利多實現後走軟,帶動台幣兌… https… Fed升…
## 3     6 娛樂     韓國女星「喬妹」宋慧喬10月嫁給宋仲基,隨即飛往西班牙度蜜月,上周六甜蜜現身IU演唱會… https… 喬妹升格…
## 4     7 財經地產 更新:新增葉倫談美股、調整標題美國聯邦準備理事會(Fed)在台北時間今凌晨3時公布利率… https… 【Fed…
## 5    10 財經地產 時代力量立委黃國昌今日在財委會上表示,臉書(Facebook;FB)在台營業,每年繳稅… https… 臉書在台…
## 6    13 財經地產 財信傳媒董事長謝金河在臉書發文表示,去年川普當選,跌破全世界的眼鏡。同樣地,菲律賓人選… https… 老謝:美…
library(jiebaR)
mixseg <- worker()
apple.seg <- lapply(apple.subset$content, function(e)segment(code = e, jiebar = mixseg))

#apple.seg[1]

library(tm)
apple.corpus <- Corpus(VectorSource(apple.seg))

doc <- tm_map(apple.corpus, removeNumbers)
## Warning in tm_map.SimpleCorpus(apple.corpus, removeNumbers): transformation
## drops documents
doc <- tm_map(doc, removePunctuation)
## Warning in tm_map.SimpleCorpus(doc, removePunctuation): transformation
## drops documents
dtm <- DocumentTermMatrix(doc)
dtm
## <<DocumentTermMatrix (documents: 357, terms: 18058)>>
## Non-/sparse entries: 62528/6384178
## Sparsity           : 99%
## Maximal term length: 18
## Weighting          : term frequency (tf)
ft <- findFreqTerms(dtm, 5)
control.list <- list(wordLengths=c(2,Inf),dictionary = ft)

new.dtm <- DocumentTermMatrix(doc,control=control.list)
dim(new.dtm)
## [1]  357 3425
as.matrix(new.dtm[1:3,1:3])
##     Terms
## Docs 一名 一審 上午
##    1    1    2    1
##    2    0    0    1
##    3    0    0    0
convert_counts <- function(x) {
  x <- ifelse(x > 0, 1, 0)
  x <- factor(x, levels = c(0, 1), labels = c("No", "Yes"))
  return(x)
}

dtm.count <- apply(new.dtm, MARGIN = 2, convert_counts)
#as.matrix(dtm.count[1:3,1:3])
dtm.count[1:3,1:3]
##     Terms
## Docs 一名  一審  上午 
##    1 "Yes" "Yes" "Yes"
##    2 "No"  "No"  "Yes"
##    3 "No"  "No"  "No"
m   <- as.data.frame(dtm.count)
sample.int(42,6)
## [1] 34 16 14  8 22 33
idx <- sample.int(2, nrow(m), replace=TRUE, prob=c(0.7,0.3))
trainset <- m[idx==1,]
testset  <- m[idx==2,]
traintitle <- apple.subset$title[idx == 1]
testtitle  <- apple.subset$title[idx == 2]
traintag <- apple.subset[idx==1,]$category
testtag  <-apple.subset[idx==2,]$category

library(e1071)

model <- naiveBayes(trainset,as.factor(traintag) )
pred <- predict(model, testset)
tb <- table(testtag, pred)
sum(pred == testtag) / length(testtag)
## [1] 0.9363636
#pred
df2 <- as.data.frame(cbind(testtag, as.character(pred),testtitle))
head(df2)
##    testtag       V2
## 1     社會     社會
## 2 財經地產 財經地產
## 3     社會     娛樂
## 4     娛樂     娛樂
## 5 財經地產 財經地產
## 6     娛樂     娛樂
##                                                  testtitle
## 1 【不斷更新】桃園工廠惡火撲滅 6人仍失聯宿舍內發現一堆白骨
## 2                       Fed宣布升息1碼 台股早盤大漲逾百點
## 3                 醉女盧小小 女警帥爆!突然霸氣送她側摔 
## 4     遭粉絲頁冒名捲「正嫻」口水戰 于美人:跟我真的無關!
## 5                鴻準砸45億入股IDG能源 布局天然氣石油商機
## 6                       蕭邦羊絨錶帶裝年輕 超薄錶速配西裝
colnames(df2) <- c('testtag', 'pred', 'title') 
df2[df2$testtag != df2$pred,]
##     testtag     pred                                              title
## 3      社會     娛樂           醉女盧小小 女警帥爆!突然霸氣送她側摔 
## 23 財經地產     娛樂 【投資動畫】月薪27K每月存股15K 他問這樣能致富嗎?
## 34     娛樂     社會         《殺人回憶》懸案上銀幕 領宋康昊登影帝寶座
## 35 財經地產     娛樂                   土銀藝文展 龍笛創辦人蔡孟夏獻寶
## 68     社會     娛樂           小嫻守正結婚在台沒登記 想離婚只有兩條路
## 93     娛樂 財經地產         Kelys & Chirp龜殼藏悅耳鳥鳴 168萬覓品味客
## 94     社會     娛樂           一下車有人墜樓掉在車頂 網友:車牌有密碼
#pred != testtag

正負情緒判斷

library(readxl)
url <- "https://raw.githubusercontent.com/ywchiu/phalanxrtm/master/data/movies.xlsx"
destfile <- "movies.xlsx"
curl::curl_download(url, destfile)
movies <- read_excel(destfile)
View(movies)


movies <- movies[(nchar(movies$content) >=10)& (movies$stars %in% c('1', '5')),]
dim(movies)
## [1] 618   5
movies$status <- as.factor(movies$status )

library(jiebaR)
mixseg    <- worker()
yahoo.seg <- lapply(movies$content, function(e)segment(code=e,jiebar=mixseg))


library(tm)

doc <- Corpus(VectorSource(yahoo.seg))
dtm <- DocumentTermMatrix(doc)
dim(dtm)
## [1]  618 4757
ft <- findFreqTerms(dtm, 5)

dtm <- DocumentTermMatrix(doc, control = list(dictionary = ft))
dim(dtm)
## [1] 618 721
convert_counts <- function(x) {
x <- ifelse(x > 0, 1, 0)
x <- factor(x, levels = c(0, 1), labels = c("No", "Yes"))
return(x)
}

dtm.count <- apply(dtm, MARGIN = 2, convert_counts)

dtm.count[1:3,1:3]
##     Terms
## Docs 不會  了    動作片
##    1 "Yes" "Yes" "Yes" 
##    2 "No"  "Yes" "No"  
##    3 "No"  "No"  "No"
m <- as.data.frame(dtm.count)
idx <- sample.int(2, nrow(m), replace=TRUE, prob=c(0.7,0.3))
trainset <- m[idx==1,]
testset  <- m[idx==2,]
traintag <- movies[idx==1,]$status
testtag  <- movies[idx==2,]$status
traincontent <- movies[idx==1,]$content
testcontent  <- movies[idx==2,]$content

library(e1071)
model <- naiveBayes(trainset,traintag )
pred <- predict(model, testset)
sum(testtag == pred, na.rm = TRUE) / length(testtag)
## [1] 0.7554348
table(testtag, pred)
##        pred
## testtag bad good
##    bad   63   15
##    good  30   76
#testcontent[testtag != pred]