検索語・文書行列
参考文献
- 岩波講座 言語の科学9 「言語情報処理」(1998)
- 石田 基広、「Rによるテキストマイニング入門」森北出版(2010)
Rのパッケージ RMeCabの関数ファミリdocMatrix, docMatrix2, docMatrixDF は、検索語・文書行列(term-document matrix)を生成する。
検索語・文書行列(または、たんに文書行列)とは、ある(形態素原形としての)term(検索語)$t_j$ が文書ファイル $d_k$ 内に現れるterm頻度(TF: term frequency)を $tf_{ij}$ としたとき、指定したカテゴリの $m$ 語からなる全てのterm $t_j (j=1\dots m)$ と検索する $n$ 個からなる全ての文書ファイル $d_k (k=1\dots n)$ についてtermの頻度を求めた次のような$m$行-$n$列からなる行列 $F=(tf_{jk})$ として定義される。 \[ F= \begin{bmatrix} tf_{11} & tf_{12} & \ldots & tf_{1n}\\ tf_{21} & tf_{22} & \ldots & tf_{2n}\\ \vdots & \vdots & \ldots & \vdots\\ tf_{m1} & tf_{m2} & \ldots & tf_{mn} \end{bmatrix} \]
検索語・文書行列を使うと、文書間の類似性(あるいは差異)を検討することができる。 ある文書集合においてあるterm群(検索語集合)が高い頻度で登場している一方で、別の文書集合では同じターム群が低い頻度でしか現れないとすれば、それら2つの文書集合は語彙の使い方において別種の文書グループとして類別してもよいだろう。
検索語・文書行列の例
次は、小川未明の「赤い鳥」、岸田 国士の「飯田の町に寄す」および 種田山頭火の「歩々到着」の3つのテキスト本文(ルビなし)を kishida.txt, ogawa.txt, santouka.txt としてフォルダ text 内に置き、関数 docMatrix の引数として以下のように、フォルダ text (したがって対象となる全テキストは kishida.txt, ogawa.txt および santouka.txt の3つ)、オプション minFreq でterm となるための規定頻度 3 を指定し、pos で(形態素としての)termとなる品詞リストを名詞・形容詞・助詞と定めた上で、その検索語・文書行列 matrix を生成した結果である。 生成した matrix は長大なので head と tail を使って、 matrix の始まり20行と末尾20行のみを表示した。
> matrix <- docMatrix("text", minFreq = 3, pos = c("名詞", "形容詞", "助詞")) file = text/kishida.txt file = text/ogawa.txt file = text/santouka.txt Term Document Matrix includes 2 information rows! whose names are [[LESS-THAN-3]] and [[TOTAL-TOKENS]] if you remove these rows, run result[ row.names(result) != "[[LESS-THAN-3]]" , ] result[ row.names(result) != "[[TOTAL-TOKENS]]" , ] > head(matrix, 20) docs terms kishida.txt ogawa.txt santouka.txt [[LESS-THAN-3]] 77 36 44 [[TOTAL-TOKENS]] 150 79 142 と 4 0 0 に 13 3 0 の 4 5 8 みな 3 0 0 を 4 3 0 町 8 0 0 飯田 5 0 0 が 0 6 4 て 0 4 0 から 0 0 3 は 0 0 4 ば 0 0 3 も 0 0 6 一 0 0 4 歩 0 0 5 > tail(matrix, 20) [[LESS-THAN-3]] 77 36 44 [[TOTAL-TOKENS]] 150 79 142 と 4 0 0 に 13 3 0 の 4 5 8 みな 3 0 0 を 4 3 0 町 8 0 0 飯田 5 0 0 が 0 6 4 て 0 4 0 から 0 0 3 は 0 0 4 ば 0 0 3 も 0 0 6 一 0 0 4 歩 0 0 5
各行の先頭(1列目)がtermで、2列目以降の数が文書ファイルごとの(形態素原形としての)termの出現頻度である。 検索語・文書行列を求めるときにオプション引数として minFreq = 3 の指定は、検索語・文書行列を構成するtermとなるための条件を指定している(無指定の場合にはデフォルト値 1 にセット)。 どれかの文書ファイルで、minFreq 回以上の頻度でなければ、検索語・文書行列のtermとして登場しない。 したがって、検索語・文書行列の各行の最大term頻度はminFreq 以上となること、および、(形態素原形としての)term頻度がある文書でminFreq 未満であるときには、term行のその文書における頻度は 0 となってしまう(実際にminFreq 回のterm頻度があったとしても 0になる)ことに注意しよう。 いいかえると、$minFreq \geqq 2$ と設定することは、ある(形態素原形としての)termを強調することになり(規定頻度 minFreq に達しないと 0 にしてしまう)、コントラストを高めた検索語・文書行列を求めることになる。 今の場合、1列目の[[LESS-THAN-3]] が示しているように、文書ファイル kishida.txt, ogawa.txt および santouka.txt に対して、各文書ファイルで2回以下しか登場しないtermの頻度合計がそれぞれ 77, 36 および 49 であったことがわかる。
一方、2列目の [[TOTAL-TOKENS]] はpos引数で指定しなかった品詞も含む、各文書テキストごとの形態素の全トークン数である(形態素原形の数ではない)。
先頭の[[LESS-THAN-3]]行と[[TOTAL-TOKENS]]行を削除して rmmatrix とするには次のようにする。
> rmmatrix <- matrix[row.names(matrix) != "[[LESS-THAN-3]]" , ] > rmmatrix <- rmmatrix[row.names(rmmatrix) != "[[TOTAL-TOKENS]]" , ] > head(rmmatrix) docs terms kishida.txt ogawa.txt santouka.txt と 4 0 0 に 13 3 0 の 4 5 8 みな 3 0 0 を 4 3 0 町 8 0 0
また、文書全体で(形態素原形としての)termの登場頻度が4以上のtermだけを取り出すには、次のように列合計関数 rowSums( ) を使う。
> matrix2 <- rmmatrix[rowSums(rmmatrix) >= 4, ] > head(matrix2, 20) docs terms kishida.txt ogawa.txt santouka.txt と 4 0 0 に 13 3 0 の 4 5 8 を 4 3 0 町 8 0 0 飯田 5 0 0 が 0 6 4 て 0 4 0 は 0 0 4 も 0 0 6 一 0 0 4 歩 0 0 5
関数 docMatrix2 では、オプション引数 minFreq の意味が docMatricx とは異なり、全文書ファイルでの規定頻度となる。 docMatrix2(... , minFreq = n, ....) の結果は、docMatrix のオプション引数で minFreq = 1(無指定でもよい)とした結果において、各行の合計が n 以上の行を取り出した
> matrix <- docMatrix(... , minFreq = 1, ...) > matrix[rowSums(matrix) >= n, ]
で得られる結果に等しい。
関数 docMatrixDF は、テキスト文書ファイルからでなく、各列が文書情報からなる表データ(データフレームとして読み込まれる)の指定列から読み込んだ文書情報に対して、検索語・文書行列を返す。 各列がある質問に対する回答記述であるような表データ(自由記述アンケートなど)の場合に使う。
検索語・文書行列の重み付け 〜 TF・IDF法
先に求めた検索語・文書行列の要素 $tf_{jk}$ は、term(検索語)$t_j$ の文書ファイル $d_k$ に対するtermの登場頻度(term頻度 TF)で定義していた。 しかしながら、term頻度によって文書ファイル群におけるそのtermの重要性を測ることは難しい。 同じ内容傾向の文書であるならば、文書量に比例してそのterm頻度はいくらでも増大してしまうからだ。
term頻度から検索語・文書行列を定めるのではなく、その行列要素を以下のようにTF・IDF法(Term Frequency / Inverse Document Frequency)によって定めるやり方が今日広く用いられている。
文書頻度(DF: document frequency)とは、あるterm $t_j$ がいくつくらいの文書に現れるかの指標で \[ df_j = \mbox{term $t_j$ を含むの文書数} \] で定義される。
TF・IDF法は、term $t_j$ の文書 $d_k$ における指標 $w_{jk}$ を次のように定義して、検索語・文書行列の要素とするのである。 \[ w_{jk} = tf_{jk} \cdot \log\frac{N}{df_j}. \] ここで、$N$ は文書群における文書数で、対数の底は 2 である。 指標 $w_{jk}$ が大きくなるのは、term $t_j$ の文書 $d_k$ における頻度 $tf_{jk}$ が高く(その文書に何度も出現し)、かつ、そのtermの文書頻度 $df_j$ が低い(特定の文書にしか出現しない)場合である。 TF・IDF法とは、そのような(形態素原形としての)termを検索語に採用すべきだという基準を与えている。
関数 docMatrix で生成する検索語・文書行列をTF・IDF法で生成するには、次のようにオプション引数 minFreq を付けずに、引数 weight = "tf*idf" を指定する。
> matrix3 <- docMatrix("text", pos = c("名詞", "形容詞", "助詞"), weight = "tf*idf") file = text/kishida.txt file = text/ogawa.txt file = text/santouka.txt > head(matrix3, 20) docs terms kishida.txt ogawa.txt santouka.txt あかるい 2.584963 0.000000 0 あつい 2.584963 0.000000 0 いま 2.584963 0.000000 0 おん 5.169925 0.000000 0 か 3.169925 1.584963 0 こそ 2.584963 0.000000 0 さかしい 2.584963 0.000000 0 さび 2.584963 0.000000 0 そ 2.584963 0.000000 0 それぞれ 2.584963 0.000000 0 たち 2.584963 0.000000 0 たま 2.584963 0.000000 0 ちかい 2.584963 0.000000 0 ちまた 2.584963 0.000000 0 と 6.339850 1.584963 0 ど 2.584963 0.000000 0 として 2.584963 0.000000 0 ども 2.584963 0.000000 0 ない 1.000000 2.000000 2 に 13.000000 3.000000 2 > tail(matrix3, 20) docs terms kishida.txt ogawa.txt santouka.txt どうし 0 0 2.584963 とも 0 0 2.584963 はけ 0 0 2.584963 はて 0 0 2.584963 も 0 0 15.509775 よう 0 0 5.169925 ワタ 0 0 2.584963 意味 0 0 2.584963 一寸 0 0 2.584963 芽 0 0 2.584963 語句 0 0 2.584963 禅門 0 0 2.584963 草 0 0 2.584963 脱落 0 0 2.584963 到着 0 0 5.169925 道 0 0 2.584963 仏 0 0 2.584963 歩 0 0 12.924813 木の芽 0 0 2.584963 旅 0 0 2.584963
TF・IDF法による検索語・文書行列の規格化
TF・IDF法によって生成した検索語・文書行列について、各文書ベクトル(2列目からの各文書列 $\vec{dv_k}$ )の長さ $||\vec{dv_k}||$ を 1 にすることを規格化(normalization)という。
ベクトル $\vec{v} = (v_1,v_2,\dots, v_n)$ において、その長さ $||\vec{v}||$ を \[ ||\vec{v}|| = \sqrt{v_1^2+v_2^2+\dots+v_n^2} \] で定義する。 このとき、ベクトル $\vec{v}$ を規格化したベクトル $\vec{v'}$ は次のように表される。 \[ \vec{v'} = \left(\frac{v_1}{||\vec{v}||}, \frac{v_2}{||\vec{v}||}, \dots, \frac{v_n}{||\vec{v}||}\right). \]
TF・IDF法による検索語・文書行列を規格化するには、関数 docMatrix で、次のように引数 weight = "tf*idf*norm" を指定する。
> matrix4 <- docMatrix("text", pos = c("名詞", "形容詞", "助詞"), weight = "tf*idf*norm") file = text/kishida.txt file = text/ogawa.txt file = text/santouka.txt > head(matrix4, 20) docs terms kishida.txt ogawa.txt santouka.txt あかるい 0.07467806 0.00000000 0.00000000 あつい 0.07467806 0.00000000 0.00000000 いま 0.07467806 0.00000000 0.00000000 おん 0.14935613 0.00000000 0.00000000 か 0.09157729 0.07450934 0.00000000 こそ 0.07467806 0.00000000 0.00000000 さかしい 0.07467806 0.00000000 0.00000000 さび 0.07467806 0.00000000 0.00000000 そ 0.07467806 0.00000000 0.00000000 それぞれ 0.07467806 0.00000000 0.00000000 たち 0.07467806 0.00000000 0.00000000 たま 0.07467806 0.00000000 0.00000000 ちかい 0.07467806 0.00000000 0.00000000 ちまた 0.07467806 0.00000000 0.00000000 と 0.18315458 0.07450934 0.00000000 ど 0.07467806 0.00000000 0.00000000 として 0.07467806 0.00000000 0.00000000 ども 0.07467806 0.00000000 0.00000000 ない 0.02888942 0.09402032 0.06566784 に 0.37556244 0.14103049 0.06566784 > tail(matrix4, 20) docs terms kishida.txt ogawa.txt santouka.txt どうし 0 0 0.08487445 とも 0 0 0.08487445 はけ 0 0 0.08487445 はて 0 0 0.08487445 も 0 0 0.50924668 よう 0 0 0.16974889 ワタ 0 0 0.08487445 意味 0 0 0.08487445 一寸 0 0 0.08487445 芽 0 0 0.08487445 語句 0 0 0.08487445 禅門 0 0 0.08487445 草 0 0 0.08487445 脱落 0 0 0.08487445 到着 0 0 0.16974889 道 0 0 0.08487445 仏 0 0 0.08487445 歩 0 0 0.42437223 木の芽 0 0 0.08487445 旅 0 0 0.08487445