F@N Ad-Tech Blog

株式会社ファンコミュニケーションズ nend・nex8・viidleのエンジニア・技術ブログ

トピックモデルを用いた文書分類をやってみた(けど評価できない

BLOG月間ということで、頑張ってBLOGを書き書きしてるy_kawasakiです。こんにちは。

随分昔に試したきり記事にしていなかったのでトピックモデルの使い方をまとめておこうと思います。

トピックモデルとは

トピックモデルとは確率モデルの一種です。つまり、何か(単語)が出現する確率を推定しています。要は似たような単語が出てくる文書の把握をします。つまり「文書における単語の出現確率」を推定するモデルになります。言ってる自分が何言ってるのか若干わかりません。
文書における単語の出現確率を推定する手法として、LDAを用います。LDAとは潜在的ディリクレ配分法(Latent Dirichlet Allocation)のことで、背景モデルとしてディリクレ分布を仮定したモデルです。

なんか、うまく説明できないので、

qiita.com

このあたりを参照していただければ幸いでございます。参照先だけで十分かもしれませんが、自分用のメモということで。

題材

我らの 青空文庫 Aozora Bunko から夏目漱石さんを選びました。ふうんいきで(なぜか変換できない)!

コーパスの作り方

基本的にはHTMLタグを取り除くだけですが、本文はdiv.classにあるのでそれだけ抜き出して、形態素解析して、STOPワードを除いて、と、いたって普通の自然言語処理の手順を踏みます。出来上がったコーパスは、こちら。

texts = [['私', '地方', 'いる', 'もの', 'ありません', '東京', '方', '平生',],
            ['昨日', '佐久間', '艇', '長', '遺書', '評し', '名文', '云', 'い', 'つた', '艇', '長', '遺書',],]

モデルの作成

import gensim

def make_lda_model(texts, titles):
  dic = gensim.corpora.Dictionary(texts)
  dic.filter_extremes(no_below=1, no_above=0.05)
  dic.filter_n_most_frequent(100)
  corpus = [dic.doc2bow(text) for text in texts]
  lda = gensim.models.ldamodel.LdaModel(corpus=corpus, num_topics=TOPICS, id2word=dic)                                                                                                                             
  # Topicの表示
  for x in lda.show_topics(-1, 5):
    print(x)

  # 各文書の所属Topic
  for t, s in zip(titles, lda[corpus]):                                                                                                                                                                           
    print(t, max(s, key=(lambda x:x[1]))) 

こんな感じでとっても簡単にModelを作成することができます。

まずは、単語の数え上げとか、をする

  dic = gensim.corpora.Dictionary(texts)

に突っ込んだあと

  dic.filter_extremes(no_below=1, no_above=0.05)
  dic.filter_n_most_frequent(100)

出現頻度で意味有りげなコーパスの作成を行います。
このあたりの数値をいろいろいじっていい感じになるように調整していきます。ただし、機械的に振り分けられているので振り分けられたのをみて人間が解釈するのはとても難しいです。そのため、ここいらの数字の最適解もよくわかりません。

  corpus = [dic.doc2bow(text) for text in texts]

で文書を単語ID列に変換して、

  lda = gensim.models.ldamodel.LdaModel(corpus=corpus, num_topics=TOPICS, id2word=dic)  

モデルを作成します。

結果

(0, '0.019*"平岡" + 0.013*"三千代" + 0.008*"門野" + 0.006*"梅子" + 0.004*"嫂"')
(1, '0.013*"宗助" + 0.008*"嫂" + 0.006*"三沢" + 0.006*"津田" + 0.005*"小六"')
(2, '0.011*"敬太郎" + 0.008*"津田" + 0.005*"千代子" + 0.004*"須永" + 0.004*"迷亭"')
(3, '0.005*"平岡" + 0.004*"小野" + 0.003*"甲野" + 0.003*"迷亭" + 0.003*"三千代"')
(4, '0.033*"津田" + 0.018*"健三" + 0.015*"宗助" + 0.009*"小林" + 0.008*"平岡"')
(5, '0.004*"小野" + 0.004*"敬太郎" + 0.003*"甲野" + 0.003*"高柳" + 0.003*"道也"')
(6, '0.010*"宗助" + 0.008*"小野" + 0.005*"嫂" + 0.005*"藤尾" + 0.005*"甲野"')
(7, '0.005*"与次郎" + 0.005*"美禰子" + 0.004*"文鳥" + 0.004*"迷亭" + 0.003*"野々宮"')
(8, '0.018*"津田" + 0.008*"健三" + 0.006*"宗助" + 0.005*"嫂" + 0.005*"秀"')
(9, '0.007*"与次郎" + 0.005*"津田" + 0.005*"美禰子" + 0.004*"小野" + 0.004*"甲野"')

各トピックを代表する単語になります。なんとなく、作品抽出されているように見えます。が、いかんせ自分の知識が足らなさ過ぎて。ぜんぜん、うまく行ってるのか自分には、わかりません。。。