y_uti のブログ

統計、機械学習、自然言語処理などに興味を持つエンジニアの技術ブログです

Term-score

前回に続き LDA の話題です。前回は、コーパスからトピックモデルを学習し、コーパスに含まれる記事が分野ごとにトピックに分かれる様子を見てみました。今度は、それぞれのトピックからどのような単語が生成されやすいかを調べてみたいと思います。

トピックごとの単語生起確率も、文書‐トピック分布と同様に計算します。すなわち、あるトピックからの単語生起確率は、各単語の生成回数にパラメータ beta を足した数の比として推定できます。

これは plda のモデルファイルから計算できるのですが、モデルファイルは行方向に単語、列方向にトピックの形式になっているため、次のように 2 パスで計算するコードを書いてみました。実は、最初は PHP で 1 パスで計算しようとしたのですが、この規模でも数万種類の単語があるので、デフォルトの設定ではメモリ不足になってしまいました。

#!/bin/bash
model=$1
beta=$2
(
  cat $model | awk -vbeta=$beta '{
    for (i = 2; i <= NF; i++) sum[i - 2] += $i;
  }
  END {
    for (i = 0; i <= NF - 2; i++) printf("%s%s", sum[i] + beta * NR, i == NF - 2 ? "\n" : " ");
  }'
  cat $model
) | awk -vbeta=$beta '
(NR == 1) {
  for (i = 1; i <= NF; i++) total[i - 1] = $i;
}
(NR > 1) {
  printf("%s ", $1);
  for (i = 2; i <= NF; i++) printf("%s%s", ($i + beta) / total[i - 2], i == NF ? "\n" : " ");
}'

これを calc_term_probability.sh として、1 番目のトピックから生起される確率の高い 10 単語を出力してみます。

$ ./calc_term_probability.sh jawiki-latest-abstract-5000.model 0.01 | sort -grsk2,2 | cut -f1 -d' ' | head -n 10
市
、
。
県
)
(
は
の
町
区

前回見たところでは、1 番目のトピックには道路や地名に関する記事が集まっていました。「市」「県」「町」「区」といった単語はその特徴をよく表しているようです。一方で、句読点や括弧、助詞といった、これといって特徴を持たない単語も上位に出現しています。これは、これらの単語は絶対的な出現頻度が高いためだと考えられます。

トピックに特徴的な単語を抽出するには、このように単語生起確率をそのまま利用するのではなく、term-score という指標を使うのがよいようです*1。これを計算するスクリプトを次のように書いてみました。

#!/bin/awk -f
{
  average = 1;
  for (i = 2; i <= NF; i++) average *= $i;
  average ^= 1 / (NF - 1);
  printf("%s ", $1);
  for (i = 2; i <= NF; i++) printf("%s%s", $i * log($i / average), i == NF ? "\n": " ");
}

このスクリプトを calc_term_score.awk として、先ほどと同じように 1 番目のトピックについて 10 単語を出力してみます。

$ ./calc_term_probability.sh jawiki-latest-abstract-5000.model 0.01 | ./calc_term_score | sort -grsk2,2 | cut -f1 -d' ' | head -n 10
市
県
町
区
号
線
道路
現在
)
(

たしかに納得の結果になりました。

*1:D. Blei and J. Lafferty. Topic Models. In A. Srivastava and M. Sahami, editors, Text Mining: Classification, Clustering, and Applications. Chapman & Hall/CRC Data Mining and Knowledge Discovery Series, 2009.