マイ・スウィート・ビーンズ

齋藤崇治。東大博士課程で政治学を研究しています。

構造的トピックモデル(stm)を論文で使うための私なりのプロトコル

トピックモデルとは、文書データの解析手法の一つである。トピックモデルを用いることにより、人手を介在させることなく、大量の文書集合から話題になっているトピックを抽出できる。また、それぞれの文書がどのようなトピックを持っているか分かる (岩田, 2015)。

 

Rでトピックモデルを分析したければ小難しい知識はあまりいらない。パッケージとして整備されているので、それを用いれば基本的な分析結果は簡単に出る。一方で、なんの知識も要らないかと言うとそんなはずはなく、パラメータの設定などで大小の主観が介入する余地がある。そして、この主観とは論文で求められる「再現性」と対極にあるものであることは論を俟たない。そのため、トピックモデルを用いた分析が、査読者が納得するに足るだけのものであることを、自分の責任で説明しなければならない。

 

ということで、今回の記事では、代表的なトピックモデルパッケージの一つであるstmパッケージを用いる際のプロトコルについて簡単にまとめたい。なお、stmパッケージの基本操作については、Roberts et al. (2019a)が詳しい。また本記事も多くはこのパッケージに拠っている。stmパッケージを用いた実践の解説書も出ているが基本的にはRoberts et al. (2019a)と、stmのr package document (Roberts et a. 2019b)で十分だと思う。 

 

基本的にはこの記事はRoberts et al. (2019a)の実践向け解説である。しかし、この記事の工夫としては、何らかのチューニングをする際の根拠となる論文も併せて紹介していることである。

 

なお、この記事の執筆者はあくまでパッケージを使うために勉強をしている一ユーザーなので、改善点あったら教えてください。

 

1 データセットへの文章の格納

まず、文書をデータフレームにするところから始まる。stmの一つの特徴は、文書に他の変数を追加することができる点である。例えば、dataというデータフレームで、documentsにトピックを推定したい文章を入れるとしよう。例えばこれが大統領演説であれば、変数としてpresident、すなわちどの大統領かを示す変数を入れることができる。それにより、文章以外にもどの大統領かから単語、文章のトピックを推定することができる。当然、分析にどの変数を入れたかは論文に書こう。

#大統領演説の仮想データ
data <- data.frame(
documents = 文章列,
president = 各大統領)

 

2 単語行列への変換

トピックモデルの基本的な発想は、文章を単語の束(bag of words)として考え、どの単語がどの単語と共にその文章内にあるか、から単語のトピックと文章のトピックを推定することである。そのため、与えられた文章から単語行列を作成し、程よい大きさにカットする必要がある。

 

例えば、"I have a dog"と"I have a cat"という文章を2つのトピックに分けることを考えよう。この時、単語の束とは、"I" "have" "a" "dog" "cat"の計5つである。それでは、この2つの文章のトピックを推定するのにこの5つの単語は全て必要だろうか?"I" "have" "a"の3つは両方の文章に共通する。そのため、トピックの推定という観点からすると不要である。そのため、これらの単語を除いた"dog"と"cat"からトピックを推定すれば良い。そのため、"I" "have" "a" "dog" "cat"からなる行列は、"dog" "cat"からなる行列に削減することができるのである。

 

まず、与えられた文章を単語行列に変換する作業を最初に行う。なお、medadata = dataとは、文書に付随させたメタデータを指す。ここでは、presidentという変数である。

 

なお、textprocessorにはremovestopwords、removepunctuationという変数が含まれており、文字通りストップワーズと!などの記号を取り除いてくれる。何もしなければデフォルトがTRUEなので勝手に取り除いてくれるのだが、論文では取り除いたことを申告しよう。しかし、実はこの作業は必ずしも本質的な部分ではない。

#単語行列化(ストップワード、!の除去)
processed <- textprocessor(data$documents, metadata = data
#, removestopwords = TRUE, removepunctuation = TRU0E
)

 

3 不必要な単語の除去

さて、問題はここからである。手元の単語行列(processed)はとてつもなく大きい。この単語行列には、ストップワードは取り除いたもののどの文章にも出てくるのでトピックの推定にはまるで役に立たない単語や、逆に少なすぎてトピックの推定に役に立たない単語がある。なので、こうした単語を取り除いて分析をスムーズに行いたい*1例えば、アメリカ大統領演説においてAmericanという単語はどの演説でもよく出て来ることは想定できる。とはいえ、このような単語を事前にリストアップするのは困難であるし、またリストアップしたとして今度は「なぜそのリストなのか」を正当化しなければならない。無理である。

 

それを自動化してくれるのがprepDocumentsだ。prepdocumentsの変数、lower.threshとupper.threshを設定することによって、その下限・上限に収まらない単語を取り除いてくれる。原理的にはこのコマンドでストップワーズも取り除くことができる。例えば次のコードで、15文書以下にしか出てこない単語、1000文書以上に出てくる単語を取り除くことができる。無論、ここで設定したlower.threshとupper.threshも論文に書こう。

out <- prepDocuments(processed$documents, processed$vocab, processed$meta, 
lower.thresh = 15, upper.thresh = 1000)

stmパッケージの著者によれば、5000超の単語数になると、トピックの推定スピードが極端に落ちることを指摘している (Roberts et al. 2019b)。 そして、Schofield et al. (2017)は、高頻出の明らかなストップワードを取り除くことによって、ストップワードリスト作成のメリット、"to reduce the amount of probability mass and smoothing of the model caused by frequent non-topic-specific terms" というメリットを享受できると指摘している。この単語数を目安にplotRemovedでthresholdを決めると良いだろう

 

4 トピック数の決定

この段階で手元には、程よく単語数を減らした単語行列(out)がある。トピックモデルにおいて最も重要なのは次のトピック数の決定である。ここに最も主観が入るからである*2

 

しかし、トピック数の決め方に決まったものがあるわけではない。私は、STM作成者が提案している方法を踏まえている。まず候補となるトピック数のレンジを決める。小さければ大雑把なトピックになるし、大きければ具体的なトピックとなる。その上で、各トピック数に対して、exclusivity、semantic coherenceと呼ばれるスコアを算出し、それをプロットする。その上で、"a model on the semantic coherence-exclusivity "frontier," that is, where no model strictly dominates another in terms of semantic coherence nad exclusivity " (Roberts et al., 2014)となるものを探す。

#比較のためのトピックモデルの実行
storage <- searchK(out$documents, out$vocab,
  K= seq(30, 150, 10),
prevalence =~ first_agency + president, data= out$meta)
#exclusivityのプロット作成、保存
pdf('output/exclusivity.pdf', height = 8)
ggplot(storage$results, aes(x = K, y = exclus ))+
geom_point()+
xlab('\n Number of Topics') +
ylab('\n Exclusivity') +
theme_bw() +
scale_x_continuous(breaks=c(50, 100, 150, 200))
dev.off()
#semantic coherenceのプロット作成、保存
pdf('output/semantic coherence.pdf', height = 8)
ggplot(storage$results, aes(x = K, y = semcoh))+
geom_point()+
xlab('\n Number of Topics') +
ylab('\n Semantic Coherence') +
theme_bw() +
scale_x_continuous(breaks=c(50, 100, 150, 200))
dev.off()

 この際のsemantic coherenceとexclusivityのスコアを図示したグラフは当然論文に入れよう。

 

5 最終的なトピックモデルの実行

さて、いよいよトピックモデルを実行する。あとはモデルを走らせるだけだ。この場合はトピック数160がベストだったとする。


set.seed(1314366346)
stm160 <- stm(documents = out$documents,
vocab = out$vocab,
data = out$meta,
#トピック数
K = 160,
#シード
seed = 555
#その他
init.type = "Spectral", prevalence =~ first_agency + president ,
)

これで、それなりに根拠を持ったトピックモデル分析の完成である。めでたしめでたし。

 

参考文献

Roberts, Margaret E., Brandon M. Stewart, Dustin Tingley. 2019a. "stm: An R Package for Structural Topic Models." Journal of Statistical Software. vol. 91. 2. 1-40.

Roberts, Margaret E., Brandon M. Stewart, Dustin Tingle, Kenneth Benoit. 2019b, "Package 'stm'." CRAN. 

Roberts, Margaret E., Brandon M. Stewart, Dustin Tingley, Christopher Lucas, Jtson Leder-Luis, Shana Kushner Gadarian, Bethany Albertson, David G. Rand. 2011. "Structural Topic Models for Open-Ended Survey Responses." American Journal of Political Science, vol. 58. 4. 1064- 1082

Schofield, Alexandra, Mans Mgnusson, David Mimno. 2017. "Pulling Stopword Removal for Topic Models." Proceedings of the 15th Conference of the European Chapter of the Association for Computational Linguistics. 2. Short Papers. 432-436 

岩田, 具治. 2015. トピックモデル. 講談社.

 

*1:実際、Schofield et al. (2017)は、こうした"frequent non-topic-specific terms"を取り除くことは分析を改善することを指摘している。

*2:一方で、これまでにも既に様々な形で主観が入っていることは読者はお分かりだろう。