ページ

2016年8月30日火曜日

【R】 東日本大震災復興の調査データ分析(5)

前回まで分析前の前処理をがんばっていた。今回からこそ、いよいよ本格的な分析に入りたい・・・と希望する。

最初に潜在意味分析について、ざっくりした解説。次に分析対象について、N-gramを対象とするべきかどうかについて検討を加える。



LSAについて
潜在意味解析

とりえあず最初は定番のWikipediaから。限界がある、という指摘はおいて、その意味するところをまとめておく。

LSAとは単純に言えば、文書ターム行列に特異値分解を施す、というものである。これにより、ターム×文書をターム×トピック+トピック×トピック+トピック×文書という3つのパートに分ける。トピックというのは潜在変数であり、それらの文書がどのようなことに関わっているのか、という概念を表現する。タームではなく概念なので、1)同じタームで違う意味という多義性の問題、2)違うタームで同じ意味という類義性の問題を同時にクリアできる。

トピックには重要なものとそうでないものが含まれているので、重要でないトピックを落とすことにより、次元圧縮が出来る。そして、次元圧縮した方が、特殊な表現の揺らぎに左右されずに、本質的な意味を捕まえることが出来る、という意味でより妥当な結論を導きやすい。

文書ターム行列を大きさt×dの行列Xと表現する。これが次のように特異値分解される。

\[
\boldsymbol{X} = \boldsymbol{T}_{n} \boldsymbol{S}_{n} \boldsymbol{D}_{n}^{\prime}
\]

大きさは、

\[
(t \times d) = (t \times n)(n \times n)(n \times d)
\]

nがトピックの数である。重要でないトピックを落とす(n→k < n)ことにより、 \[ \boldsymbol{X} \simeq \boldsymbol{T}_{k} \boldsymbol{S}_{k} \boldsymbol{D}_{k}^{\prime} \] \[ (t \times d) = (t \times k)(k \times k)(k \times d) \] とする。Skはデータ全体の情報のうちどのくらいを活用したのか、またトピック間の関係(直交行列なので、お互いに独立だが)を示している。Tkはターム間の関係・類似性を示している。多義的なタームは、いろいろなトピックと結びつくことになる。またトピックを限定すれば、多義性を取り除いたターム間の関係(共起性に近い性質、つまり同一文書にいっしょに出現する度合い)を示すことになる。Dkは文書間の類似性を示すことになり、これを使って文書の自動分類が出来る・・・ものと期待される。

N-gramについて

日本語テキストの自動分類のための特徴素抽出手法の比較
R による文書分類入門

さて、まずは出発点である文書ターム行列を準備するところから始まるが、これには1)「Bag-of-words」=「Unigram」を重視する立場と、2)N-gramという複数のタームの組みを重視する立場がある。前者の立場は、このように割り切るからこそ、文書という複雑なものを分析できるのだ、という主張が込められているし、文書だけではなく任意の複雑なものを分析できる可能性を秘めているのだ、と熱く将来性を語る傾向も出てくる。後者の立場は、複雑なものを割り切れば、それだけ分析は雑になる、ということを主張する。例えば、上のリンク最初の文献は、N=2のDigramが最も精度良く分析できている、と結論している。

私自身は、どちらの立場をとるべきかは、分析の目的とデータの特徴によって変わる、と見ている。例えば、一つの文書が長く、多数のタームが含まれている場合は、文書の間の違いを際立たせるためにUnigramではなく、N-gramを使うべきと考える。今回私が分析したいのは、短文が多数あるので、Unigramで十分なのではないかと思っている。また実際の計算上もN-gramはやっかいだなあと感じている。

被災者の生活の回復:2016年8月

試しに分析してみた。

source("LSA.txt")

docu0 <- c()
for(target in 1:length(lr2)){
 docu0 <- c(docu0,TMin.PrintC(lr2[target]))
}

dt <- docMatrixDF(docu0)

head(dt[-c(1:28),])
dt <- dt[-c(1:28),]
dt.svd <- svd(dt)

str(dt.svd)
dt.svd.r <- dimReducShare(dt.svd, share=0.5,dt)
str(dt.svd.r)

tm <- myCosine(t(dt.svd.r$tk))

rownames(dt)

target <- 121
rownames(dt)[target]
sort(tm[which(tm[,target] > 0.5),target],decreasing=TRUE)

1行目は、右の本の付録を活用させてもらった。

具体的には、dimReducShare(次元縮約)とmyCosine(コサイン距離の計算)で使っている。8行目はRMeCabの関数を使い、とりあえず重みなしで文書ターム行列を作成している。10~11行は数字と記号を削ったところ。

15行目で次元縮約している。その前後で、データ構造を調べている。これによると、ターム数497、文書数173の特異値分解により、文書数と同じ173のトピックが得られている。これを縮約して、49次元まで削った。

> str(dt.svd)
List of 3
 $ d: num [1:173] 9.83 7.74 7.36 6.54 5.89 ...
 $ u: num [1:497, 1:173] -0.000865 -0.011991 -0.005051 -0.009585 -0.005686 ...
 $ v: num [1:173, 1:173] -0.0299 -0.1087 -0.0485 -0.0725 -0.0594 ...
> str(dt.svd.r)
List of 3
 $ tk: num [1:497, 1:49] -0.000865 -0.011991 -0.005051 -0.009585 -0.005686 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : chr [1:497] "いち早い" "おかげ" "お願い" "お住い" ...
  .. ..$ : NULL
 $ dk: num [1:173, 1:49] -0.0299 -0.1087 -0.0485 -0.0725 -0.0594 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : chr [1:173] "OBS.1" "OBS.2" "OBS.3" "OBS.4" ...
  .. ..$ : NULL
 $ sk: num [1:49] 9.83 7.74 7.36 6.54 5.89 ...

18行でコサイン距離を計算できたので、最後の22~24行であるタームに近いタームのリストを取り出している。例えば、

> target <- 121
> rownames(dt)[target]
[1] "漁業者"
> sort(tm[which(tm[,target] > 0.5),target],decreasing=TRUE)
   漁業者  リタイア      深刻    震災後      生産    労働者    労働力 
1.0000000 0.7471990 0.7471990 0.7471990 0.7471990 0.7471990 0.7471990 
     従来    加工場  インフラ      生業    本格的      養殖      カキ 
0.6164382 0.6148368 0.6148368 0.6148368 0.6148368 0.6148368 0.6148368 
     漁船    水産業      不足      時期 
0.6148368 0.5884460 0.5790817 0.5709175 

これを見ると、「漁業者」というタームについて、「リタイア」、「労働者」、「労働力」、「不足」という言葉がつながり、それが「深刻」と認識されているらしいことが分かる。それ以外は、「漁船」、「水産業」、「養殖」など、セットで出てくるタームが多い。

別の例も見てみる。

> target <- 93
> rownames(dt)[target]
[1] "学校"
> sort(tm[which(tm[,target] > 0.5),target],decreasing=TRUE)
     学校      運動      震災      校庭      使用      空室 
1.0000000 0.9897045 0.9137940 0.9059933 0.8725220 0.5368867 

「学校」というタームに、「運動」、「校庭」、「使用」などがくっついている。これは、「学校」の「校庭」が仮設住宅に「使用」されていて子供たちが「運動」できない、という訴えを表現している。

まとめ

時々、おかしなタームがくっついているが、まあまあの結果と言えようか。

改善を要することとして、

  • 似たようなタームがあっても、LSAが勝手に同一視してくれるわけではない。そうしてくれるには文書数が少ないようである。なので、前処理の段階で辞書整備で解決すべきであろう。
  • 重みなしで計算してみたが、重みを加えた方が結果が良くなるだろうか?試してみる必要がある。
  • 1タームごとに見るのではなく、一挙に全体像をみたい。共起グラフのようなグラフ表示は可能だろうか?
  • トピックの意味づけ、つまりS行列の解釈は可能なのだろうか。対角行列だからSだけ見ていてもダメなのだが。
  • 文書数を増やす。まず経済分野と防災分野の追加。他の期間の追加は、ベイズ分析が出来てからか?
  • 最終目的である文書の分類を、上の課題が解決したらやってみる。