TFIDF Example
library(tm)
library(tmcn)
library(Matrix)
library(wordcloud)
Something before reading
- 這份 code 使用的 coding style 是遵照 Google R Coding Style
- 看到不懂的 function 多用 ?
<function name>
去查詢
- 直接把每行 code 複製貼上是最沒有效率的學習方法,同學可以試著想想每行 code 背後代表的意義
Segmentation, Term Document Matrix
- 讀檔
- 把 [1] [2] … 這種維基百科的註解去掉(文本是從 wiki 複製下來的)
- 把 docs 轉成 corpus
- 斷詞
- 把斷詞結果轉換成 term-document matrix
- 偷看一下轉換後的結果
docs <- readLines("structuralism.txt")
docs <- gsub("\\[[0-9]+\\]", "", docs)
docs.corpus <- Corpus(VectorSource(docs))
docs.seg <- tm_map(docs.corpus, segmentCN)
docs.tdm <- TermDocumentMatrix(docs.seg, control = list())
inspect(docs.tdm)
## <<TermDocumentMatrix (terms: 435, documents: 14)>>
## Non-/sparse entries: 619/5471
## Sparsity : 90%
## Maximal term length: 13
## Weighting : term frequency (tf)
## Sample :
## Docs
## Terms 10 11 12 13 14 3 4 6 7 8
## 心理學 0 0 7 3 0 0 0 0 0 0
## 文化 0 0 0 0 0 4 1 0 0 0
## 文學 0 4 0 0 1 1 0 3 0 0
## 以及 1 0 3 0 1 2 0 0 0 0
## 故事 0 0 0 0 8 0 0 0 0 0
## 研究 1 2 2 3 0 1 1 1 1 1
## 科學 0 1 0 0 0 0 0 1 1 0
## 結構 6 1 0 0 6 4 2 0 1 1
## 結構主義 3 3 0 0 0 2 5 1 1 0
## 語言 0 0 0 0 0 0 0 0 3 1
TFIDF Counting
- 計算每個詞的 term frequency
- 定義計算 idf 的 function
- 計算 idf
- tfidf = tf * idf
- 看一下結果
docs.tf <- apply(as.matrix(docs.tdm), 2, function(doc) {doc / sum(doc)})
idf.function <- function(word_doc) { log2( (length(word_doc)+1) / nnzero(word_doc) ) }
docs.idf <- apply(docs.tdm, 1, idf.function)
docs.tfidf <- docs.tf * docs.idf
head(docs.tfidf)
## Docs
## Terms 1 2 3 4 5 6 7 8 9 10 11
## structuralism 0.09767226 0 0 0.0000000 0 0 0 0 0 0 0.00000000
## 了解 0.09767226 0 0 0.0000000 0 0 0 0 0 0 0.00000000
## 二十<a5> 0.09767226 0 0 0.0000000 0 0 0 0 0 0 0.00000000
## 下半 0.09767226 0 0 0.0000000 0 0 0 0 0 0 0.00000000
## 大前提 0.09767226 0 0 0.0000000 0 0 0 0 0 0 0.00000000
## 之間 0.04767226 0 0 0.0312605 0 0 0 0 0 0 0.04434629
## Docs
## Terms 12 13 14
## structuralism 0.00000000 0 0
## 了解 0.00000000 0 0
## 二十<a5> 0.00000000 0 0
## 下半 0.00000000 0 0
## 大前提 0.00000000 0 0
## 之間 0.02166921 0 0
Query of Words
- 定義查詢函數
- 查詢 “結構”, “人類學”, “整體” 三個詞在各篇文章的 tfidf 值
query.tfidf <- function(q){
q.position <- which(rownames(docs.tfidf) %in% q)
q.tfidf <- docs.tfidf[q.position, ]
return (q.tfidf)
}
query.tfidf(c("結構", "人類學", "整體"))
## Docs
## Terms 1 2 3 4 5 6 7
## 結構 0.04534453 0 0.04969264 0.02973412 0 0.0000000 0.01813781
## 整體 0.09767226 0 0.00000000 0.00000000 0 0.0000000 0.00000000
## 人類學 0.00000000 0 0.03180723 0.00000000 0 0.0504767 0.00000000
## Docs
## Terms 8 9 10 11 12 13 14
## 結構 0.01929554 0 0.07663864 0.02109048 0 0 0.04572558
## 整體 0.00000000 0 0.00000000 0.00000000 0 0 0.00000000
## 人類學 0.00000000 0 0.06540643 0.00000000 0 0 0.00000000
Cosine Similiarity
- 定義「計算 x, y 兩向量 cosine 值」函數
- 計算 “各篇文章的 tfidf 向量” 與 “第一篇文章 tfidf 向量” 的 cosine 值
cos <- function(x, y){
return (x %*% y / sqrt(x %*% x * y %*% y))[1, 1]
}
# compare with first doc
docs.cos.sim <- apply(docs.tfidf, 2, cos, y = docs.tfidf[, 1])
docs.cos.sim
## 1 2 3 4 5 6
## 1.000000000 0.031479857 0.071134636 0.032901470 0.144244508 0.022938287
## 7 8 9 10 11 12
## 0.073859797 0.012212186 0.029992818 0.031548444 0.052831432 0.010399877
## 13 14
## 0.005784062 0.032081762
Wordcloud
- 計算個詞彙的詞頻總和
- 把單詞-詞頻對應存入 data frame
- 畫出文字雲
f <- sort(rowSums(docs.tfidf), decreasing = T)
docs.df <- data.frame(
word = names(f),
freq = f
)
wordcloud(docs.df$word, docs.df$freq, scale=c(5,0.1), colors=brewer.pal(8, "Dark2"))