主に情報検索の分野で使われるTF-IDFについて勉強したので、そのメモ。
さらに、scikit-learnで用意されているものを使ってTF-IDFを計算してみます。
環境
MeCabについては
関連リンク
sklearn.feature_extraction.text.CountVectorizer — scikit-learn 0.19.2 documentation
sklearn.feature_extraction.text.TfidfTransformer — scikit-learn 0.19.2 documentation
sklearn.feature_extraction.text.TfidfVectorizer — scikit-learn 0.19.2 documentation
4.2. Feature extraction — scikit-learn 0.19.2 documentation
TF-IDF
TF-IDFについてかるくまとめてみます。
TF-IDFとは、Term Frequency - Inverse Document Frequencyの略で自然言語をベクトルで表現する方法のひとつ、ある文書を特徴づける重要な単語を抽出したいときに有効な手法です。
TF-IDFの求め方は次のとおりです。
tfとidfを掛けることによりtfidfを求められます。
Term Frequency
tfとはある単語のある文書における出現頻度のことです。tfでは出現頻度が多い単語ほど重要になります。
tfの求め方は次のとおりです。
以下の例からtfを求めてみます。
例えば、2つの文A, Bがあったとします。
A: 私は醤油ラーメンととんこつラーメンが好きです。
B: 私はとんこつラーメンと味噌ラーメンが好きです。
この2つの文を形態素解析して名詞だけを取り出すと下のようになります。
A: ['私', '醤油', 'ラーメン', 'とんこつ', 'ラーメン', '好き']
B: ['私', 'とんこつ', 'ラーメン', '味噌', 'ラーメン', '好き']
文書Aにおける単語ラーメンと醤油のtfを求めてみます。
式より、
tf(ラーメン, 文書A)= 2 / 6 = 0.33
tf(醤油, 文書A)= 1 / 6 = 0.17
ラーメンのほうが値が高くなっており文書Aではラーメンが重要な単語であることを意味します。
文書Bでも同じことが言えます。
Inverse Document Frequency
idfとはある単語がいくつの文書で使われているかを表し、色々な文書によく使われる単語は重要ではありません。すなわち、めったにお目にかかれない単語ほど高い値になります。
idfの求め方は次のとおりです。
tfと同じ例でidfを求めてみます。
総文書数は文書Aと文書Bだけなので2になります。
idf(ラーメン)= log( 2 / 2 ) + 1 = 1
idf(醤油)= log( 2 / 1 ) + 1 = 1.3
ラーメンより醤油のほうが出現頻度が低いので高い値になっています。
Term Frequency - Inverse Document Frequency
再びTF-IDFに話は戻ります。
上の例の文書からtfとidfについて求めることができたので、今度はTF-IDFの計算をしてみます。
TF-IDF = tf(ラーメン, 文書A)* idf(ラーメン)= 0.33 * 1 = 0.33
TF-IDF = tf(醤油, 文書A)* idf(醤油)= 0.17 * 1.3 = 0.22
ラーメンのほうが若干値が高くなりました。
tfよりもTF-IDFで計算したほうが醤油の値が大きくなり、ラーメンと醤油の値の差が小さくなりました。
出現頻度が多く(tfの値が大きい)さらに、いくつもの文書で出現しない(idfの値が大きい)単語ほどTF-IDFの値は大きくなり、ある文書Dを特徴づける単語となります。
そのため、出現頻度が多いラーメンの値が大きいままで、出現頻度が少ないものの文書Bにしか出現しない醤油の値がtfよりも大きくなったのではないかと思います。
データの用意
ここからはプログラムを使ってTF-IDFを計算してみます。
まずは、TF-IDFを計算するデータ(文書)を用意します。今回用いるデータは以前書いた記事で作成したデータです。
データの中身はTwitterの対話データから抽出されたツイートになっていて、ロシアW杯日本代表に関するツイートになっています。全部で742のツイートがあります。
これら742のツイートを形態素解析したのちに、print()
を使ってファイルに書き込んでいます。
今回は新たに作成したtfidf-dataset.txt
を使ってTFIDFを計算します。
下は生成されたtfidf-dataset.txt
の中身の一例。
原口 と 槙野 も 先発 だ と 期待 し て ます 。 槙野 は 出る と 思う ん です が 、 原口 は もしか する と 乾 の サブ かも ねー 。 どちら に し て も 頑張っ て ー ! 今日日 本戦 ! ! ! たのしみ ! 頑張れ ! コロンビア ! それ ! もう 日本 出 なく て いい 。 経費 の 無駄 本田 スタメン 外し た の は 英断 だ けど 中盤 誰 が 守備 すん ねん w この メンツ なら 原口 だ な 。
プログラムを書く
scikit-learnを使ったTFIDFの計算方法は2通りあります。ひとつはCountVectorizerとTfidfTransformerを使う方法、もうひとつはTfidfVectorizerを使う方法です。
それぞれについて説明する前にまずはデータを読み込みます。
データはリストになっていて、中身は分かち書きされた文字列になっています。
方法① CountVectoizerとTfidfTransformer
CountVectorizer
CountVectorizerはテキストを単語に分割し、その出現頻度をカウントして行列に変換してくれる。
TfidfTransformer
TfidfTransformerはCountVectorizerで作った行列からtfもしくはtfidfを正規化して計算してくれる。デフォルトでは、tfidfを計算するようになっている。
使い方
tfidfを計算するプログラム。
手順としては
- CountVectorizerで単語の出現頻度を計算
- TfidfTransformerで単語の出現頻度からtfidfを計算
あとはtfidfを使って煮るなり焼くなり好きにする。
オマケ
tokens_pattern
CountVectorizerのインスタンスを作るときにtokens_patternにu'(?u)\\b\\w+\\b'
を渡しています。これをすることにより単語をカウントする際、長さ1の単語もカウントするようになります。デフォルトでは長さ1の単語はカウントされません。
vocabulary_
カウントした単語が辞書になっている。keyは単語でvalueは単語ID。
get_feature_names()
出現した単語がリストに入っている。
toarray()
すべての文書における単語の出現頻度をnumpy型の配列に変換する。
下の例では10個の文書における単語の出現頻度を表示している。
方法② TfidfVectorizer
TfidfVectorizer
CountVectorizerとTfidfTransformerの役割をこれひとつでしてくれる。
使い方
データを渡す、だたそれだけ。
CountVectorizerとTfidfTransformerで紹介したオマケはTfidfVectorizerでも使用可です。
次回
TF-IDFからCosine Similarityを計算したい。
計算してみました。