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

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

R環境で小説のテキストマイニングをやってみたら、○○○な結末になった件【その1: 夏目漱石の小説「坊っちゃん」を使った、テキストの前処理編】

はじめに

テキストマイニングは、簡単に言うと、テキストデータを定量的に扱って、有益な情報を抽出するデータマイニング手法の1つです。 このようなテキストの情報解析では、自然言語処理、形態素解析、キーワード抽出、共起分析、ネットワーク可視化、機械学習、感情分析など、様々な分析手法が用いられます。 近年では各種のAPIやWebスクレイピングなどを利用して、ウェブやSNS、地図上のクチコミからテキストデータを取得して、テキストマイニングに活用されています。 『R環境で小説のテキストマイニング』の連載シリーズでは、テキストマイニングの活用事例として、小説テキストを対するテキストマイニングの基本的な手法を概説しています。 各分析手法は、フリーソフトであるR言語やPythonのパッケージを主に用いて実施しています。

そもそも、自分が小説とかを通読するのが苦手ということもあって、 テキストマイニングの観点からせめて、 「マイニング結果から小説を読んだ気になれる」とか、「全体のあらずじとか、盛り上がっている章とかがまぁまぁ分かる」といった辺りのことができるかどうかを以前から調査したかった経緯があります。 そのため、テキストマイニング、形態素解析、ネットワーク可視化や感情分析による文脈解釈とかを扱う連載記事を書くことにしました。

他方、そもそもの小説を読む醍醐味とかは完全に無くなりますけどね。。。

テキストマイニングの対象小説は、夏目漱石の「坊っちゃん」にしました。 理由は後ほど説明します。それでは、テキストマイニングの世界に行ってらっしゃい。

連載シリーズの目次

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


【その1: 夏目漱石の小説「坊っちゃん」を使った、テキストの前処理編】に関する内容をやっていきます。

実行環境

#ターミナル上の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を起動して実行しています。

1. 青空文庫、対象小説の紹介

夏目 漱石が執筆した小説の無料公開リスト

実は、夏目 漱石の小説本文は、ウェブ上で無料公開されています

著作権切れ作品を集めた、青空文庫というサイトにアップされています。

www.aozora.gr.jp

例えば、「坊っちゃん」とかもhtml形式のテキストで公開されていて読むことができます。

www.aozora.gr.jp

「坊っちゃん」のテキスト部分をWebスクレイピングで取得すると、 R環境上でテキストを利用できます。

次のセクションでは、Webスクレイピングによるテキストの取得から、テキスト情報の前処理を扱います。

2. 「坊っちゃん」のテキストの前処理

上画像の「坊っちゃん」のテキスト部分をWebスクレイピングで取得します。ご丁寧に漢字にルビがふってあるので、それらを前処理で除去していきます

また、テキスト部分のXpathは「/html/body/div[3]"」になります。

それでは、R環境を立ち上げて以下を実行して、テキストをざっくり取得します。

#パッケージのインストール
install.packages(c("rvest", "magrittr", "stringr"))
#ロード
library(rvest); library(magrittr); library(stringr)

##テキストのWebスクレイピング
#「坊っちゃん」のURL
Bochan_url <- "https://www.aozora.gr.jp/cards/000148/files/752_14964.html"

#ウェブサイトを確認するなら
#browseURL(Bochan_url)

#テキストの取得
Bochan_text <- Bochan_url %>%
  rvest::read_html() %>%
  rvest::html_nodes(xpath = "/html/body/div[3]") %>%
  rvest::html_text()

#取得結果の表示
str(Bochan_text)
#chr "一\r\n\r\n 親譲(おやゆず)りの無鉄砲(むてっぽう)で小供の時から損ばかりしている。小学#校に居る時分学校の二階"| __truncated__

テキストを取得すると、 「\r\n\r\n」「\r\n」とかの改行記号があったり、 ルビ部分があったりします。 組み込み関数やstringrパッケージを使って、それらを除いていきます。

#テキストを章ごとに分割する
#\r\n\r\n
#\\p{Han}は「漢字」指定、. は「任意文字」指定
Bochan_text.sp <- stringr::str_split(Bochan_text, 
                                     pattern = "\\p{Han}\r\n\r\n.|\\p{Han}\\p{Han}\r\n\r\n.")[[1]][-1]

#改行「\r\n」を消す
Bochan_text.sp.rn <- gsub(pattern="\r\n |\r\n", 
                          replacement="",
                          Bochan_text.sp)  

#ルビ部分を削除する
Rub <- c(".", "..", "...", "....", ".....", "......", ".......", "........", ".........", "..........", "................", ".................")

#ルビの任意文字数
nchar(Rub)
#[1]  1  2  3  4  5  6  7  8  9 10 16 17

#実行
for(n in Rub){
Bochan_text.sp.rn <- gsub(pattern=paste0("[(]", n, "[)]"), 
                        replacement="",
                        Bochan_text.sp.rn)  
}

#文字数
nchar(Bochan_text.sp.rn)
#[1]  7499  5983  5821  7583  7495 10412 10071  7133  8409  8058  9806

#先頭20文字のテキストの表示
stringr::str_sub(Bochan_text.sp.rn[1], start = 1, end = 20) 
#[1] "親譲りの無鉄砲で小供の時から損ばかりして"
stringr::str_sub(Bochan_text.sp.rn[2], start = 1, end = 20) 
#[1] "ぶうと云って汽船がとまると、艀が岸を離れ"
stringr::str_sub(Bochan_text.sp.rn[3], start = 1, end = 20) 
#[1] "いよいよ学校へ出た。初めて教場へはいって"

こんな感じで、章ごとにテキストを分けた、11要素のベクトル空間ができます。

次に、テキストファイルとして書き出して、GitHubにアップします。

#テキストファイルへの書き出し
#全文
write(Bochan_text.sp.rn, file = "Bochan_text.all.txt", append = F)
#saveRDS(Bochan_text.sp.rn, file = "Bochan_text.all.Rds")

#第1章
write(Bochan_text.sp.rn[1], file = "Bochan_text.1st.txt", append = F)
#saveRDS(Bochan_text.sp.rn[1], file = "Bochan_text.1st.Rds")

#第2章
write(Bochan_text.sp.rn[2], file = "Bochan_text.2nd.txt", append = F)
#saveRDS(Bochan_text.sp.rn[2], file = "Bochan_text.2nd.Rds")

坊ちゃんの第1章のテキスト

坊ちゃんの第2章のテキスト

処理したテキストの保存

次に、先ほど処理したテキストをGitHubからダウンロードする方法をのせています。

##GitHubにアップロードしたファイルたち
#テキスト全文
file_path_all <- "https://raw.githubusercontent.com/kumeS/Blog/master/R_text_analysis/R_01/Bochan_text.all.txt"
browseURL(file_path_all)
Bochan_text.all <- readLines(con = file(file_path_all))

#テキスト全文: Rds version
Rds_path_all <- "https://github.com/kumeS/Blog/raw/master/R_text_analysis/R_01/Bochan_text.all.Rds"
download.file(url=Rds_path_all, destfile = basename(Rds_path_all))
Bochan_text.all <- readRDS(basename(Rds_path_all))


##第1章
file_path_1st <- "https://raw.githubusercontent.com/kumeS/Blog/master/R_text_analysis/R_01/Bochan_text.1st.txt"
browseURL(file_path_1st)
Bochan_text.1st <- readLines(con = file(file_path_1st))

#第1章: Rds version
Rds_path_1st <- "https://github.com/kumeS/Blog/raw/master/R_text_analysis/R_01/Bochan_text.1st.Rds"
download.file(url=Rds_path_1st, destfile = basename(Rds_path_1st))
Bochan_text.all <- readRDS(basename(Rds_path_1st))


##第2章
file_path_2nd <- "https://raw.githubusercontent.com/kumeS/Blog/master/R_text_analysis/R_01/Bochan_text.2nd.txt"
browseURL(file_path_2nd)
Bochan_text.2nd <- readLines(con = file(file_path_2nd))

#第2章: Rds version
Rds_path_2nd <- "https://github.com/kumeS/Blog/raw/master/R_text_analysis/R_01/Bochan_text.2nd.Rds"
download.file(url=Rds_path_2nd, destfile = basename(Rds_path_2nd))
Bochan_text.all <- readRDS(basename(Rds_path_2nd))

まとめ

Html形式のテキストを取得して、ざっくりとテキストの前処理までをやってみました。

次回からは、形態素解析も取り入れて、テキスト解析を行います。

テキスト処理の関連記事

skume.net

skume.net

skume.net

skume.net

skume.net

skume.net

参考資料

skume.net

skume.net

skume.net