はじめに
計量言語学・計量文献学に著者推定・著者判別というものがあります。文書中の単語の出現頻度などから、著者の癖といったものを割り出すことで著者を識別します。この手法は、作者不明作品の執筆者の推定やスパムメールの判別に応用されます。
この記事では、太宰治作品の登場人物の台詞に対してこの手法を用います。各登場人物の台詞中の「助詞」と「読点」の組み合わせの頻度を基にして各話者の類似度を測定して分類を行います。
【目次】
・分析対象テキスト
作品 | 登場人物 | 属性 | 性別 |
---|---|---|---|
人間失格 | 葉蔵 | 主人公 | 男 |
人間失格 | 堀木 | 主人公の友人 | 男 |
斜陽 | かず子 | 主人公 | 女 |
斜陽 | かず子の母 | 主人公の母 | 女 |
斜陽 | 直治 | 主人公の弟 | 男 |
ヴィヨンの妻 | 私 | 主人公 | 女 |
ヴィヨンの妻 | 大谷 | 主人公の夫 | 男 |
グッド・バイ | 田島 | 主人公 | 男 |
グッド・バイ | キヌ子 | 主人公の知人 | 女 |
作品ごとに以下の形式のcsvファイルと、ここから話者ごとにA列を取り出したtxtファイルを用意しました。
テキストの抽出や話者の判別はKindleのハイライトとメモ機能を使って、自(分の手を)動(かすこと)で行いました。
話者分類
・会話関係のネットワーク
「話し手」⇒「聞き手」という形式でネットワークグラフ化しました。A⇔Bとなっていればお互いに声をかけたということです。矢印が丸くなって話者自身を指しているのは独り言の類いです。
3作品が一人称視点の小説であることもあってか想定以上に主人公に集中している印象です。
Rコード(クリックで展開)
library(igraph) library(tidyverse) # ファイルの読み込み df <- read.csv("ファイル名.csv") names(df) <- c("conversation", "speaker", "listener") net_df <- df %>% select(speaker, listener) %>% distinct() # 描画 net <- graph_from_data_frame(net_df) tkplot(net, vertex.size = 0, vertex.label.cex = 1, vertex.label.family = "JP1")
ネットワークグラフやbi-gramの作成についての詳しい解説はこの記事をご参照ください。
・「助詞」-「読点」の組み合わせの頻度
特徴量として読点前の助詞の数を用います。読点を打つ位置には特にルールがないため、執筆者の癖が出やすいようです。また、助詞は文書の内容の影響を受けにくいため、作品の内容によって会話の内容が似通ってしまうことを回避できるかと思います。登場人物ごとで総語数が異なるので、1,000語当たりの数にしています。
クラスタリングに用いる前にグラフして確認します。
ある程度差異が見られるように感じますがどうでしょうか。続いてクラスタリングを行います。
Rコード(クリックで展開)
library(RMeCab) library(purrr) library(magrittr) library(dplyr) library(stringr) library(ggplot2) folder_name <- "フォルダ名" file_path <- paste(folder_name, list.files(folder_name), sep = "/") ngram_df <- data.frame(N1 = "は") # 受け皿の用意 for(i in seq_along(file_path)){ # 形態素解析 dat <- RMeCabText(file_path[i]) # ファイルパスを指定 tag <- str_remove_all(file_path, "^.*_|.txt") # 2-gramを作成 token <- map_chr(dat, extract(1)) # 文書中の形態素 pos <- map_chr(dat, extract(2)) # 品詞 lemma <- map_chr(dat, extract(8)) # 見出し語化された形態素 lemma[lemma == "*"] <- token[lemma == "*"] # 見出し語化されなかった単語を置き換える term_df <- data.frame(TERM = lemma, POS = pos, stringsAsFactors = FALSE) n <- nrow(term_df) ngram1 <- data.frame(N1 = term_df[1:(n-1), 1], N2 = term_df[2:n, 1], POS1 = term_df[1:(n-1), 2], POS2 = term_df[2:n, 2]) # 要素を1つずらした2列で2-gramとなる # 語句の抽出 ngram2 <- ngram1 %>% group_by(N1, N2, POS1, POS2) %>% summarise(FREQ = n()) # 頻度の集計 ngram2$FREQ <- ngram2$FREQ / sum(ngram2$FREQ) * 1000 # 相対頻度化 ngram3 <- ngram2 %>% filter(POS1 == "助詞" & N2 == "、") %>% ungroup() %>% select(N1, FREQ) names(ngram3) <- c("N1", tag[i]) ngram_df <- full_join(ngram_df, ngram3, by = "N1") } ngram_df[is.na(ngram_df)] <- 0 ngram_df2 <- gather(ngram_df, tag, value, -N1) # 描画 ggplot(ngram_df2, aes(tag, value, fill = tag)) + geom_bar(stat = "identity", position = "dodge")+ facet_wrap( ~ N1, scales = "free") + theme(axis.text.x = element_text(size = 0)) + labs(x = "", y = "", fill = "")
・クラスタリング
類似度の高いもの同士を組み合わせていくことで、グループを作っていきます。
葉蔵と田島の男主人公やカズ子と私の女主人公がそれぞれグループ化されています。概ね男と女のグループに分かれた様ですが、そう解釈するなら男グループに紛れた母の存在が気になります。
Rコード(クリックで展開)
cluster <- ngram_df[, -1] # 語の列を落とす # 類似度を測る den <- cluster %>% t() %>% dist() %>% hclust("ward.D2") %>% as.dendrogram() # 描画 plot(den)
・おまけ
助詞の頻度のみを特徴量としてクラスタリングを行った結果です。
見事に男女で分かれました。
相対頻度をみると、「かしら」「さえ」「わ」は分かりやすく女性キャラに偏っていますね。女言葉を使っているというのもキャラの特徴と言えば特徴ですが、男性側のクラスタも綺麗ではないですし、素直に助詞の種類を参考書に従って絞るべきでした。
とはいえ、今後に期待できそうな結果に思えます。
今回はここまでです。
参考書籍
- 小林雄一郎(2018)『Rによるやさしいテキストマイニング[活用事例編]』オーム社
おわりに
分類できなければ登場人物を書き分けられていて作者すげぇ、分類できればスターシステムだぁ。と、どっちでもおいしいネタと思って挑戦しました。書籍や論文では主に作者の識別をされていますが、まぁ私はオタクなので作者だけでなくキャラにも注目したくなる訳です。
分析結果に関しては、まだ4作品分しかデータを作れていないのでなんとも言えません。今年中には全作品分用意したいなぁ。とは思っていますが、作業がめんどいこと…。他の作者でも試して、界隈の人の視界に入ってみたいという思惑もあったりしますので、早急に進めたい。
Rの時代が始まる!その初日なのでRを使った自己紹介的な記事をば、と思って書きました。こういったテキストマイニングに興味があって現在R共々勉強しております。趣味の方の当面の目標はハロプロ楽曲の歌詞分析です!
では、新しい時代もよろしくお願いします!最後まで読んでいただきありがとうございました。