○はじめに
Rを使って機械学習の分野で言うところの教師なし学習である階層型クラスター分析を行います。
テキスト中に使われている文字・単語の頻度を用いて各テキストの類似性を測り、グループに分類していきます。階層型というのは、1つずつのデータを小さなグループ(クラスター)にして、そしてさらにグループ同士をグループとし、最後は全てを含む大きなグループとなる。このように段階を踏んでクラスターを形成していく手法です。詳しい説明は参考書籍をご参照ください。
・分析データ
ハロプロのグループ「こぶしファクトリー」と「つばきファクトリー」の歌詞。詳しくは前回の記事をご参照ください。
・主な参考書籍
『Rによるやさしいテキストマイニング』小林雄一郎,オーム社
○テキストのクラスタリングとデンドログラムの作成
・処理コード
パッケージ
library(RMeCab) library(magrittr) library(dplyr) library(stringr) library(dendextend)
準備
#ファイルを指定 folder_name1 <- "1人目フォルダ名" folder_name2 <- "2人目フォルダ名" file_name12 <- c(list.files(folder_name1), list.files(folder_name2)) file_path12 <- c(paste(folder_name1, list.files(folder_name1), sep = "/"), paste(folder_name2, list.files(folder_name2), sep = "/"))
特徴語の頻度表を作成
cluster1 <- term_100100[,1] #特徴語とする組を選び、語だけを抽出 for(i in 1:length(file_path12)) { #形態素解析 tmp1 <- docDF(file_path12[i]) #頻度表を整形 colnames(tmp1) <- c("TERM", "FREQ") #後の処理のために列名を統一 tmp2 <- tmp1 %>% filter(!grepl("\\s", TERM)) #doc()で空白が紛れ込むので取り除く tmp2$FREQ <- tmp2$FREQ / sum(tmp2$FREQ) * 1000 #相対頻度に変更 cluster1 <- left_join(cluster1, tmp2, by = "TERM") #特徴語に含まれる語の頻度のみを残 } cluster2 <- cluster1 cluster2[is.na(cluster2)] <- 0 #NAを0にする cluster2 <- cluster2[, -1] #TERMの列を落とす
特徴語については前回の記事を読んでね。left_join()
で特徴語(cluster1$TERM)と一致するものだけをデータフレーム(cluster1)に残すことができる。観測頻度で処理するならtmp2$FREQ <- tmp2$FREQ / sum(tmp2$FREQ) * 1000
をコメントアウトする。
クラスタリングの段階では特徴量となる値だけでいいので、TERM列を削る(本当は転置した時に行名にするのが理想かも)。
これは文字レベルの処理になっているので単語レベルであれば次のようにする。
cluster1 <- term_200200[,1] #特徴語とする組を選び、語だけを抽出 for(i in 1:length(file_path12)) { #形態素解析 tmp1 <- docDF(file_path12[i], type = 1) #, pos = c("名詞", "動詞", "形容詞", "形容動詞") #頻度表を整形 colnames(tmp1) <- c("TERM", "POS1", "POS2", "FREQ") #後の処理のために列名を統一 tmp2 <- tmp1 %>% filter(!grepl("\\s", TERM)) %>% #doc()で空白が紛れ込むので取り除く select(TERM, FREQ) %>% #品詞は使わない group_by(TERM) %>% #別の品詞として集計された同単語を統合 summarise(FREQ = sum(FREQ)) #統合時に頻度を加算 tmp2$FREQ <- tmp2$FREQ / sum(tmp2$FREQ) * 1000 #相対頻度に変更 cluster1 <- left_join(cluster1, tmp2, by = "TERM") #特徴語に含まれる語の頻度のみを残 } cluster2 <- cluster1 cluster2[is.na(cluster2)] <- 0 #NAを0にする cluster2 <- cluster2[, -1] #TERMの列を落とす
docDF()
に引数type = 1
とすると結果が単語レベルで返ってくる。単語レベルにすると品詞情報も付随して返ってくるので、colnames(tmp_freqency_table)
のところをc("TERM", "POS1", "POS2", "FREQ")
とする。品詞情報が加わることで同じ単語が品詞的には別の語としてカウントされることがあるので、それを統合する(ここでは品詞に注目していないため)。
クラスタリングとデンドログラムの作成
colnames(cluster2) <- str_remove(file_name12, ".txt") #列名をテキスト名に戻す den <- cluster2 %>% t() %>% dist() %>% hclust("ward.D2") %>% as.dendrogram() #dist()で距離を測り、hclust()で類似度を測る lab.col2 <- ifelse(substr(labels(den), 1,3) == "kbs", "#099800", "#FD9556") #色指定 labels_colors(den) <- lab.col2 plot(den, main = "グラフのタイトル")
特に必要ないので拡張子の部分を落とす。
次以降の処理のためにt()
で転置する。各列の特徴量を基にdist()
で文書間の距離を測る。その距離(非類似度)からhclust()
で近しい(似ている)文書を探索する。類似度の測定には種類があるが、今回は"ward.D2"
でウォード法を使う。最後にas.dendrogram()
でデンドログラムのプロットをするためにデータの形式を変換する。
(正直よく分かってないのですが)kbsのところにテキスト名から一致させたい語を指定すると、カラーコード("#099800", "#FD9556")の前の方の色に、不一致なら後の方の色になる。
最後にplot()
で分析結果を可視化する。
・使用文字によるクラスタ
相対頻度
テキストを文字レベルに区切り、文書ごとの出現頻度を基に各文書をグループ化していく。
この結果が一番良いっぽいので詳しく見てみる。
各文書の総語数の平均は542.8語で文字種類の平均は153.0語のところ、1文書内に含まれていた特徴語の平均はそれぞれ44.8語(特徴語56語)、72.3語(129語)、101語(258語)だった。(数値の詳細は下の項目を展開してください。)
2つずつグループ化できている数で言うと、相対頻度の文字レベルで特徴語を平均文字種の半数程度とした分析が一番良かったということになる。(本当に??)
詳細(クリックで展開)
## FILE_NAME TOKENS TYPES N_5050 N_100100 N_200200 ## 1 kbs_a1a.txt 430 124 38 55 73 ## 2 kbs_a1e.txt 617 154 44 68 95 ## 3 kbs_a1g.txt 607 134 50 83 104 ## 4 kbs_a1i.txt 508 175 42 68 102 ## 5 kbs_a1l.txt 313 114 34 51 77 ## 6 kbs_a1o.txt 583 210 47 90 127 ## 7 kbs_a1q.txt 621 156 45 73 103 ## 8 kbs_s0a.txt 430 144 42 68 92 ## 9 kbs_s0b.txt 339 88 38 56 69 ## 10 kbs_s1a.txt 605 190 45 77 112 ## 11 kbs_s2a.txt 615 156 44 77 105 ## 12 kbs_s2b.txt 567 167 46 77 108 ## 13 kbs_s2c.txt 602 131 41 68 89 ## 14 kbs_s3a.txt 669 193 45 81 120 ## 15 kbs_s3b.txt 647 174 49 72 116 ## 16 kbs_s4a.txt 487 124 42 64 90 ## 17 kbs_s5a.txt 714 211 53 85 131 ## 18 kbs_s5b.txt 434 105 42 67 91 ## 19 kbs_s6a.txt 717 150 44 74 107 ## 20 kbs_s6b.txt 349 121 43 68 91 ## 21 tbk_a1b.txt 625 160 49 84 107 ## 22 tbk_a1f.txt 488 153 43 65 99 ## 23 tbk_a1i.txt 573 140 49 72 101 ## 24 tbk_a1m.txt 430 164 47 71 108 ## 25 tbk_a1q.txt 612 190 45 80 116 ## 26 tbk_a1r.txt 303 116 45 69 84 ## 27 tbk_s0a.txt 359 109 45 67 86 ## 28 tbk_s0b.txt 724 190 51 87 130 ## 29 tbk_s0c.txt 265 95 42 58 72 ## 30 tbk_s1a.txt 772 202 51 90 130 ## 31 tbk_s1b.txt 771 145 47 70 99 ## 32 tbk_s1c.txt 666 199 50 84 119 ## 33 tbk_s2a.txt 896 180 48 77 107 ## 34 tbk_s2b.txt 418 110 39 58 78 ## 35 tbk_s2c.txt 333 128 38 67 86 ## 36 tbk_s3a.txt 508 162 44 73 103 ## 37 tbk_s3b.txt 467 173 46 78 112 ## 38 tbk_s3c.txt 530 177 44 79 109 ## 39 tbk_s4a.txt 488 138 44 68 89 ## 40 tbk_s4b.txt 543 186 47 73 112 ## 41 tbk_s4c.txt 628 133 47 71 92
観測頻度
対象が歌詞なので総語数にそこまで差が出ないだろう、またある程度の長い短いもその文書の特徴と言えるのでは、との考えのもと実際の頻度である観測頻度でも分析を行う。
やはり、相対頻度の方が良いように感じる。クラスタの結果についての明確な評価基準はないようです(現在理論面も勉強途上です!)。
・使用単語によるクラスタ
相対頻度
テキストを単語レベルに区切り、文書ごとの出現頻度を基に各文書をグループ化していく。
各文書の総語数の平均は294.8語で文字種類の平均は126.5語のところ、1文書内に含まれていた特徴語の平均はそれぞれ32.5語(特徴語66語)、45.5語(139語)、62.0語(298語)だった。(数値の詳細は下の項目を展開してください。)
詳細(クリックで展開)
## FILE_NAME TOKENS TYPES N_5050 N_100100 N_200200 ## 1 kbs_a1a.txt 253 105 27 35 49 ## 2 kbs_a1e.txt 344 126 35 48 63 ## 3 kbs_a1g.txt 261 98 27 42 53 ## 4 kbs_a1i.txt 312 162 41 54 69 ## 5 kbs_a1l.txt 168 88 20 32 46 ## 6 kbs_a1o.txt 301 146 28 39 54 ## 7 kbs_a1q.txt 374 140 39 56 74 ## 8 kbs_s0a.txt 232 98 26 30 41 ## 9 kbs_s0b.txt 163 63 20 29 39 ## 10 kbs_s1a.txt 365 152 37 50 70 ## 11 kbs_s2a.txt 301 130 30 39 57 ## 12 kbs_s2b.txt 272 126 30 42 57 ## 13 kbs_s2c.txt 329 108 35 48 65 ## 14 kbs_s3a.txt 325 143 30 45 59 ## 15 kbs_s3b.txt 362 141 35 45 60 ## 16 kbs_s4a.txt 247 87 27 36 47 ## 17 kbs_s5a.txt 413 171 40 50 73 ## 18 kbs_s5b.txt 254 104 36 54 75 ## 19 kbs_s6a.txt 376 122 28 41 65 ## 20 kbs_s6b.txt 193 103 24 41 60 ## 21 tbk_a1b.txt 337 135 36 54 72 ## 22 tbk_a1f.txt 274 118 26 41 55 ## 23 tbk_a1i.txt 312 127 35 52 76 ## 24 tbk_a1m.txt 245 136 32 45 64 ## 25 tbk_a1q.txt 279 139 31 45 65 ## 26 tbk_a1r.txt 171 103 38 52 63 ## 27 tbk_s0a.txt 207 110 36 54 69 ## 28 tbk_s0b.txt 379 158 37 53 70 ## 29 tbk_s0c.txt 154 77 27 36 47 ## 30 tbk_s1a.txt 410 167 35 52 78 ## 31 tbk_s1b.txt 388 129 35 51 66 ## 32 tbk_s1c.txt 433 200 39 47 60 ## 33 tbk_s2a.txt 467 177 40 56 82 ## 34 tbk_s2b.txt 218 89 29 38 53 ## 35 tbk_s2c.txt 184 94 30 38 48 ## 36 tbk_s3a.txt 279 133 36 48 65 ## 37 tbk_s3b.txt 268 134 32 42 60 ## 38 tbk_s3c.txt 311 140 35 46 67 ## 39 tbk_s4a.txt 277 123 34 51 66 ## 40 tbk_s4b.txt 305 156 37 54 69 ## 41 tbk_s4c.txt 342 127 36 54 73
相対頻度,品詞限定(名詞,動詞,形容詞,形容動詞)
歌詞の内容によって特徴が出ているのでは、との考えのもと意味的役割を持つ名詞・動詞・形容詞・形容動詞に限定した分析を行う。
意味の面から特徴が見えるのではと考えた訳だが、仮にそれがあったとしても歌詞という特性上様々な表現を用いるだろう。この分析では類語をいくら使っていても文書として似ているという結果にならないため、うまくいかないのではないかと考える。むしろ高頻度な助詞といった品詞の差の方が、頻度面で特徴をよく表すのだろう。また文字レベルだと、熟語が漢字単位に分解されることで、ある程度の類語の類似性が反映されたのではと考える。
TF-IDF
その単語がどれだけ文書を特徴づけているのかに注目した値であるので、TF-IDFも基準として使い分析を行う。
今回は、両グループそれぞれの文書から別々にTF-IDFを求め、それぞれの上位の語を特徴語とした。その上で、クラスタリングの際には両グループを合わせてTF-IDFを出し、その数値を基に分析を行った。TF-IDFの適当な扱い方が思いつかず、正直中途半端な処理の仕方だったのではと感じている。
全体を通してkbk_s4aがグループを作っていないのが気になった。
○おわりに
そもそもは、こぶしの曲は「今は大変でも前を向いて頑張っていこう」つばきは「センチメンタルな乙女の恋心」な歌詞だから(感覚的主観)、意味ベースで客観的にそれぞれの特徴を示したいというのが動機でした。今回の結果では、意味的機能を持つ名詞・動詞等よりも助詞も含めた全ての単語を特徴語として使う方が良さそうだし、なんなら文字単位で分類するのが一番高精度っぽいのはちょっとね…。まぁ元々歌詞の表現には幅を持たせてグループ感を形作っていく訳だし、類語単位でなければコンセプトや方向性のようなものを示せないだろうなとは思っていましたがね。あー早く分散表現完全に理解したい!
あとは、分類したい(別の特徴を持って欲しい)両グループから特徴語をそれぞれ選んで全体の特徴語とするのは、ひょっとしてズルなのでは?と思ったり。機械学習の様々な手法を通しで試してみるという今回の目的からは、分類しやすくなるのは理解のためにはいいのかなーとか思いつつ、このまま進めます。でもどうしたらいいでしょうか、全体の上位語を特徴語とするのが素直だとは始めから思っていたのですが、特徴語を含まない文書が出てきたら困るので今回の方法にした。他には文書ごとに上位一定語数を選ぶ方法は考えましたけども。
うーむ独学つらい誰か良い教材教えてください―。いえさっさと教科書3巻(活用事例編)の著者推定などなどをやればいいんです。文字の2-gramを特徴語に!
とまぁ、多少ネガティブになりましたが、心の方では楽しんでるのでガンガン進めます―!前にこの分析をした時よりもかなり良くなったしね。では、次回は線形判別分析によるカテゴライゼーションです。最後まで読んでいただきありがとうございました。次回もよろしくお願いします。