京橋のバイオインフォマティシャンの日常

南国のビーチパラソルの下で、Rプログラムを打ってる日常を求めて、、Daily Life of Bioinformatician in Kyobashi of Osaka

R環境で小説のテキストマイニングをやってみたら、○○○な結末になった件【その4: テキストマイニングと形態素のワードクラウド】

はじめに: 『R環境で小説のテキストマイニング』の連載シリーズ

テキストマイニングは、テキストデータから、有益な情報を取り出すデータマイニング手法の1つです。 テキストデータに対する情報解析では、自然言語処理、形態素解析、キーワード抽出、共起分析、ネットワーク可視化、機械学習、感情分析など、様々な分析手法が用いられます。 近年では、TwitterのつぶやきやSNS、地図上のクチコミなどのテキストデータも活用されています。

この記事は、夏目漱石の「坊っちゃん」が対象小説で、 テキストマイニングと形態素のワードクラウドを扱った内容となっています。

連載シリーズの目次

1. 青空文庫、対象小説の紹介
2. 「坊っちゃん」のテキストの前処理
3. 形態素解析と辞書設定
4. 形態素解析と複合語抽出 (ルールベース抽出、pytermextract)
5. テキストマイニングと形態素のワードクラウド
6. テキストマイニングとN-gramのネットワーク表現(章ごとの関係性とか)
7. 文章の感情分析(感情ポジネガ分析とか、英語感情対応表とか、ML-askとか)
8. ミクロとマクロなテキスト解析〜応用篇として内容を考え中〜


この記事では、「5. テキストマイニングと形態素のワードクラウド」に関する内容をやっていきます。

まずは、実行環境

#ターミナル上のR環境
R version 4.1.2 (2021-11-01) -- "Bird Hippie"
Copyright (C) 2021 The R Foundation for Statistical Computing
Platform: aarch64-apple-darwin20.6.0 (64-bit)

#RStudioターミナル上のR環境
R version 4.1.2 (2021-11-01) -- "Bird Hippie"
Copyright (C) 2021 The R Foundation for Statistical Computing
Platform: x86_64-apple-darwin17.0 (64-bit)

今回、M1 Mac・RStudioでRMeCabパッケージがうまく動作せず、 形態素解析の部分はターミナルからR実行した結果を使っています。

形態素のワードクラウドに関するイントロダクション

ワードクラウド(Wordcloud)は、 テキスト中の語彙の出現頻度をもとに、 テキスト中の頻出語を視覚的に表現する手法の1つです。 各語彙を頻度に比例する大きさで表す、視覚表現をとっています。

さて、「ワードクラウドをどのように作るか?」ということですが、

  1. テキストの取得・前処理

  2. テキストの形態素解析

  3. ワードクラウドによる形態素頻度の可視化

の3ステップになります。

「1」のテキストの取得と前処理が終われば、 次に、「2」でテキストをそれぞれ語彙に分解する必要があります。 いわゆる、形態素解析のステップです。 具体的には、RMeCab + neologd辞書を使って、形態素解析していきます。

「1. テキストの取得・前処理」と「2. テキストの形態素解析」の具体的な実行方法については、 過去の記事で大変分かりやすくまとめていますので、そちらを参照してください。

skume.net

skume.net

さっそく、「3. ワードクラウドによる形態素頻度の可視化」のステップに進みます。

はじめに、「坊っちゃん」の第1章テキストでの形態素解析済みの結果(result1.Rds or result1.txt)を GitHubからダウンロードして、R環境に読み込むところをやります。

RMeCab形態素解析済みの結果の読み込み

.Rdsをロードする場合

.RdsファイルをR環境に読み込む場合には、一度ローカルにファイルをダウンロードする必要があります。

##形態素解析の結果(result1.Rds)をR環境にロードする
#URL先の定義
Rds_path <- "https://github.com/kumeS/Blog/raw/master/R_text_analysis/R_02/result1.Rds"

#ローカルディレクトリにダウンロード
download.file(url=Rds_path, destfile = basename(Rds_path))

#Rdsの読み込み
result1r <- readRDS(file = "result1.Rds")

.txtをロードする場合

.txtファイルの場合には、WebのURLから直接読み込むことができます。 そのため、テキストの方が手数としては少なくなります。

##形態素解析の結果(result1.txt)をR環境にロードする
#URL先の定義
Txt_path <- "https://github.com/kumeS/Blog/raw/master/R_text_analysis/R_02/result1.txt"

#txtの読み込み
result1t <- read.table(file=Txt_path, header = T, sep = "\t")

結局は、以下のように同じ結果がロードされます。 好みで、ファイル読み込みの方法を決めてください。

#ヘッド表示
head(result1r)
#  parts    mor
#1  名詞 親譲り
#2  助詞     の
#3  名詞 無鉄砲
#4  助詞     で
#5  名詞   小供
#6  助詞     の

#詳細表示
str(result1r)
#'data.frame': 4870 obs. of  2 variables:
# $ parts: chr  "名詞" "助詞" "名詞" "助詞" ...
# $ mor  : chr  "親譲り" "の" "無鉄砲" "で" ...

#ヘッド表示
head(result1t)
#  parts    mor
#1  名詞 親譲り
#2  助詞     の
#3  名詞 無鉄砲
#4  助詞     で
#5  名詞   小供
#6  助詞     の

#詳細表示
str(result1t)
#'data.frame': 4870 obs. of  2 variables:
# $ parts: chr  "名詞" "助詞" "名詞" "助詞" ...
# $ mor  : chr  "親譲り" "の" "無鉄砲" "で" ...

変数result1の中身は、2列 x 4870行のデータフレーム形式のデータで、 4870個の形態素(mor列)とそれに対応する品詞(parts列)の情報が含まれています。 これは、RMeCab + neologd辞書を使った形態素解析の結果です。

ワードクラウドによる形態素頻度の可視化

さて、ワードクラウドを作成するのに使う、関連パッケージをインストールしていきます。

#wordcloud2とhtmlwidgetsのインストール
install.packages(c("wordcloud2", "htmlwidgets"))
library(wordcloud2); library(htmlwidgets)

#カラーパレット
install.packages("colorspace")
library("colorspace")

次に、ワードクラウドによる可視化を行う、実際のRコードを紹介します。

品詞情報をもとに、名詞のみ抽出した場合、形容詞や動詞も含めた場合、複合語判定の結果を含めた場合など、 複数パターンのワードクラウドを作成していきます。 また、「平仮名1文字の形態素を除く」とか、「形態素頻度の補正」とか、「出現数上位20%のみ抽出」とかの前処理もやっています。

品詞情報から「名詞」のみ抽出した場合のワードクラウド

まずはじめに、坊ちゃんの第1章のテキストデータを使って、 「名詞」のみ抽出した形態素の結果 に対して、ワードクラウドを実行します。

#Rdsのロード結果を使用します。
result1 <- result1r

#品詞から「名詞」のみ抽出した場合
result2 <- result1[result1$parts %in% c("名詞"),]

#品詞の集計
table(result2$parts)
#名詞 
#1292

#平仮名1文字の形態素を除く
result3 <- result2[!base::grepl(pattern="^[あ-ん]$", result2$mor),]

#集計
Dat <- data.frame(mor=names(table(result3$mor)),
                  Freq=as.numeric(table(result3$mor)))

#頻度1回を除く
Dat <- Dat[Dat$Freq != 1,]

#形態素頻度を0~1の値に補正
Dat$FreqR <- round(Dat$Freq/max(Dat$Freq), 4)

#出現数上位20%のみ抽出
res <- quantile(Dat$FreqR, probs = seq(0, 1, 0.1))
Dat0 <- Dat[Dat$FreqR > as.numeric(res[9]),]

#抽出の結果
dim(Dat0)
#[1] 38  3

#表示
head(Dat0[order(Dat0$Freq, decreasing = T),])
#     mor Freq  FreqR
#12  おれ   43 1.0000
#356   清   37 0.8605
#183   兄   27 0.6279
#63  もの   26 0.6047
#115   何   25 0.5814
#255   事   22 0.5116

#wordcloud2.jsによるワードクラウド作成
Dat1 <- wordcloud2(Dat0[,c("mor", "FreqR")],
                   shape="circle",
                   size=0.8,
                   gridSize =  1,
                   fontFamily="YuGothic",
                   color = "random-light",
                   ellipticity = 0.75,
                   backgroundColor = "black")

#ワードクラウド結果の表示
Dat1

#ワードクラウドの保存
htmlwidgets::saveWidget(Dat1, "./WordCloud_Dat0.html", selfcontained = F)
20220815011642
クリックすると、結果がブラウザで表示されます。

簡単にRコードの解説をします。 まず、%in%を使って、名詞だけ抽出しています。 次に、平仮名1文字の形態素を除き、単語のリストとカウントを作成しています。 そして、各前処理を行い、各単語、それぞれに対応する頻度と補正頻度を持つデータフレームを作成しています。

最終的に、ワードクラウドを実行する、wordcloud2関数には、 形態素とその補正頻度「Dat0[,c("mor", "FreqR")]」をINPUTとして与えています。 また、オプションとしては、shape、fontFamily、ellipticity、backgroundColorなどを設定しています。

品詞情報から「名詞」「形容詞」「動詞」を抽出した場合のワードクラウド

坊ちゃんの第1章のテキストデータを使って、 「名詞」と「形容詞」と「動詞」を抽出した形態素の結果 に対して、ワードクラウドを実行します。

#Rdsのロード結果を使用します。
result1 <- result1r

#品詞から「名詞」と「形容詞」と「動詞」を抽出
result2 <- result1[result1$parts %in% c("名詞", "形容詞", "動詞"),]

#品詞の集計
table(result2$parts)
#形容詞   動詞   名詞 
#    87    775   1292

#平仮名1文字の形態素を除く
result3 <- result2[!base::grepl(pattern="^[あ-ん]$", result2$mor),]

#品詞の集計
table(result3$parts)
#形容詞   動詞   名詞 
#    87    774   1255

#集計
Dat <- data.frame(mor=names(table(result3$mor)),
                  Freq=as.numeric(table(result3$mor)))

#頻度1回を除く
Dat <- Dat[Dat$Freq != 1,]

#形態素頻度を0~1の値に補正
Dat$FreqR <- round(Dat$Freq/max(Dat$Freq), 4)

#出現数上位20%のみ抽出
res <- quantile(Dat$FreqR, probs = seq(0, 1, 0.1))
Dat0 <- Dat[Dat$FreqR > as.numeric(res[9]),]

#抽出の結果
dim(Dat0)
#[1] 52  3

#表示
head(Dat0[order(Dat0$Freq, decreasing = T),])
#     mor Freq  FreqR
#57  する   89 1.0000
#173 云う   50 0.5618
#16  いる   46 0.5169
#22  おれ   43 0.4831
#98  なる   37 0.4157
#542   清   37 0.4157

#wordcloud2.jsによるワードクラウド作成
Dat1 <- wordcloud2(Dat0[,c("mor", "FreqR")],
                   shape="circle",
                   size=0.8,
                   gridSize =  1,
                   fontFamily="YuGothic",
                   color = "random-light",
                   ellipticity = 0.75,
                   backgroundColor = "black")

#ワードクラウド結果の表示
Dat1

#ワードクラウドの保存
htmlwidgets::saveWidget(Dat1, "./WordCloud_Dat1.html", selfcontained = F)
20220815012628
クリックすると、結果がブラウザで表示されます。

品詞情報から「名詞」と「複合語」を抽出した場合のワードクラウド

坊ちゃんの第1章のテキストデータを使って、 「名詞」と「複合語」を抽出した形態素の結果 に対して、ワードクラウドを実行します。

#Rdsのロード結果を使用します。
result1 <- result1r

#複合語抽出: Compound_calc()関数を使います
source("https://raw.githubusercontent.com/kumeS/Blog/master/R_text_analysis/R_03/Compound_calc.R")

#実行
result1c <- Compound_calc(result = result1)

#品詞から「名詞」と「形容詞」と「動詞」を抽出
result2 <- result1c[result1c$parts %in% c("名詞", "複合語"),]

#品詞の集計
table(result2$parts)
#複合語   名詞 
#   137   1003

#平仮名1文字の形態素を除く
result3 <- result2[!base::grepl(pattern="^[あ-ん]$", result2$mor),]

#品詞の集計
table(result3$parts)
#複合語   名詞 
#   137    972

#集計
Dat <- data.frame(mor=names(table(result3$mor)),
                  Freq=as.numeric(table(result3$mor)))

#頻度1回を除く
Dat <- Dat[Dat$Freq != 1,]

#形態素頻度を0~1の値に補正
Dat$FreqR <- round(Dat$Freq/max(Dat$Freq), 4)

#出現数上位20%のみ抽出
res <- quantile(Dat$FreqR, probs = seq(0, 1, 0.1))
Dat0 <- Dat[Dat$FreqR > as.numeric(res[9]),]

#抽出の結果
dim(Dat0)
#[1] 30  3

#表示
head(Dat0[order(Dat0$Freq, decreasing = T),])
#     mor Freq  FreqR
#12  おれ   42 1.0000
#367   清   37 0.8810
#71  もの   26 0.6190
#189   兄   25 0.5952
#121   何   23 0.5476
#264   事   22 0.5238

#wordcloud2.jsによるワードクラウド作成
Dat1 <- wordcloud2(Dat0[,c("mor", "FreqR")],
                   shape="circle",
                   size=0.8,
                   gridSize =  1,
                   fontFamily="YuGothic",
                   color = colorspace::rainbow_hcl(nrow(Dat0), c = 60, l = 60),
                   ellipticity = 0.75,
                   backgroundColor = "black")

#ワードクラウド結果の表示
Dat1

#ワードクラウドの保存
htmlwidgets::saveWidget(Dat1, "./WordCloud_Dat2_1st.html", selfcontained = F)
20220815012817
クリックすると、結果がブラウザで表示されます。

坊ちゃん第2章以降のワードクラウドによる可視化

次に、第2章以降でワードクラウドを試してみた結果を紹介します。

坊ちゃんの第2章のテキストデータを使って、 「名詞」と「複合語」を抽出した形態素の結果 に対して、ワードクラウドを実行します。

上記の実行が冗長なので、 ワークフローを自作関数化して(wdCloud.R関数という名前)、 実行を簡略化しています。

坊ちゃん第2章のワードクラウド

#txtファイルを読み込んで使用します。
Txt_path <- "https://github.com/kumeS/Blog/raw/master/R_text_analysis/R_02/result2.txt"
result1 <- read.table(file=Txt_path, header = T, sep = "\t")

#wdCloud.Rのロード
source("https://raw.githubusercontent.com/kumeS/Blog/master/R_text_analysis/R_04/wdCloud_test.R")

#ワードクラウド実行
Dat1 <- wdCloud.R(result1)

#ワードクラウド結果の表示
Dat1

#ワードクラウドの保存
htmlwidgets::saveWidget(Dat1, "./WordCloud_Dat2_2nd.html", selfcontained = F)
20220815013043
クリックすると、結果がブラウザで表示されます。

坊ちゃん第3章のワードクラウド

続いて、坊ちゃん第3章のワードクラウドです。

#txtファイルを読み込んで使用します。
Txt_path <- "https://github.com/kumeS/Blog/raw/master/R_text_analysis/R_02/result3.txt"
result1 <- read.table(file=Txt_path, header = T, sep = "\t")

#wdCloud.Rのロード
source("https://raw.githubusercontent.com/kumeS/Blog/master/R_text_analysis/R_04/wdCloud_test.R")

#ワードクラウド実行
Dat1 <- wdCloud.R(result1)

#ワードクラウド結果の表示
Dat1

#ワードクラウドの保存
htmlwidgets::saveWidget(Dat1, "./WordCloud_Dat2_3rd.html", selfcontained = F)
20220815013128
クリックすると、結果がブラウザで表示されます。

同じなので、以下省略。。。

https://kumes.github.io/Blog/R_text_analysis/R_04/WordCloud_Dat2_4th.html

https://kumes.github.io/Blog/R_text_analysis/R_04/WordCloud_Dat2_5th.html

https://kumes.github.io/Blog/R_text_analysis/R_04/WordCloud_Dat2_6th.html

https://kumes.github.io/Blog/R_text_analysis/R_04/WordCloud_Dat2_7th.html

https://kumes.github.io/Blog/R_text_analysis/R_04/WordCloud_Dat2_8th.html

https://kumes.github.io/Blog/R_text_analysis/R_04/WordCloud_Dat2_9th.html

https://kumes.github.io/Blog/R_text_analysis/R_04/WordCloud_Dat2_10th.html

https://kumes.github.io/Blog/R_text_analysis/R_04/WordCloud_Dat2_11th.html

坊ちゃん第1〜11章のワードクラウドの結果まとめ

 

過去に坊ちゃんを読んだことなるような、無いような、内容はほとんど覚えてませんので、 ワードクラウド見た感じの印象をツラツラと書いてます。

全体を通して、「おれ」はよく出てきてますね。「おれ」中心の話なんでしょうね。

第1章は、「おれ」「清」「兄」とかが目立つ。清が兄なんかな、分からんけど。

第2章はなんか和茶和茶してますね。中学校が舞台なのか、教師とか校長とか、山嵐も出てくるようです。

第3章のクラウドはやや控えめですね。学校の隣に東京とあり、誰か転校生がやってくるのか? ワードクラウドでは、語彙の位置関係は関係ないですけども。

第4章は「バッタ」と「宿直」、第5章は「赤シャツ」、第6章は「山嵐」、第7章は「模試」が目立ちます。 模試とあるので試験勉強してのかな。山嵐ってなんだっけ?風のこと?柔道の技のこと?

第8章で、もう一度「赤シャツ」が出てくる、「婆さん」「月給」もでてくるようだ。 「月給」とか、なんだか現実的な話っぽいね。

さらに、第9章で「うらなり君」と「送別会」、第10章で「喧嘩」、 第11章ではまたも「山嵐」で、「新聞屋・新聞」が新しく出てくる。 転校生の「うらなり君」喧嘩したのか?最後に、新聞バイトしてるのか?謎は深まるばかり。。   ワードクラウドを見ただけだと、テキトーな考察になってしまいましたね。

まとめ

今回は、テキストマイニングの一例として、 坊ちゃんの各章のテキストデータをワードクラウドで可視化してみました。

結構簡単にワードクラウドを実行できるので、 色々な条件で見方を変えて、ぜひ色々と試してみてください。

参考資料

www.karada-good.net

Wordcloud2 introduction