本日は、TF-IDFについて簡単に勉強してみたので、それのまとめです。
- TF-IDFとは
- Term Frequency
- Inverse Document Frequency
- TF-IDF(Term Frequency - Inverse Document Frequency)を求める
- scikit-learnで計算してみる
TF-IDFとは
Term Frequency - Inverse Document Frequencyの略で自然言語をベクトルで表現する方法のひとつであり、ある文書を特徴づける重要な単語を抽出したいときに有効な手法です。
TF-IDFの求め方は次のとおりです。
tfとidfを掛けることによりtfidfを求められます。まとめると、下記のように表すことができます。
このtf(Term Frequency)とidf(Inverse Document Frequency)について説明します。
Term Frequency
tfはある単語のある文書における出現頻度のことです。tfでは、出現頻度が多い単語ほど重要になります。
tfの求め方は下記の通りです。
例えば下記のような文書があった場合、
A:私はラーメンが好きだ。中でも味噌ラーメンが一番好きだ。
B:私は焼きそばが好きだ。しかしラーメンはもっと好きだ。
これを形態素解析してみると
A:['私', 'ラーメン', '好き', '中', '味噌', 'ラーメン', '一番', '好き']
B:['私', '焼きそば', '好き', 'しかし', 'ラーメン', 'もっと', '好き']
というようになります。この文書Aで、ラーメン
と味噌
のtfを計算してみます。
上記から、この文書では味噌よりもラーメンの方が重要な単語ということが分かります。
Inverse Document Frequency
idfは、ある単語がいくつの文書で使用されているかを表しています。例えば、「私」や「これ」、「しかし」などの単語はいろんな文書で使用される可能性があり、出現頻度が高いのは当然です(=あまり重要な単語ではない)。そのような普遍的に出現する単語ではなく、特定の文書にしか登場しないレア単語であればあるほど、idf値は高くなります。
idfの求め方は下記の通りです。
tfと同じ例でidfを求めてみると、
ラーメンより味噌の方が全文書からの比率として出現頻度が低い(=レア)なので、idfの値が高くなっています。
TF-IDF(Term Frequency - Inverse Document Frequency)を求める
上記の例より、tfとidfについて求めることができたので、最後のTF-IDFを求めてみます。
簡単に表にまとめてみます。
A:私はラーメンが好きだ。中でも味噌ラーメンが一番好きだ。
B:私は焼きそばが好きだ。しかしラーメンはもっと好きだ。
- | tf | idf | TF-IDF |
---|---|---|---|
ラーメン | 0.33 | 1 | 0.33 |
味噌 | 0.17 | 1.3 | 0.22 |
tf値とTF-IDF値を比較したときに、「ラーメン」に関しては同じ値ですが、「味噌」に関してはTF-IDFの方が値が大きくなっています。これは、文書Aにおいて「味噌」という単語のレア度が高い(=文書を特徴付ける単語になっている)ためだと考えられます。
scikit-learnで計算してみる
上記の例で、実際にコーディングしてみます。(都合上、上記と若干単語表現を変えています)
from sklearn.feature_extraction.text import TfidfVectorizer import pandas as pd df = pd.DataFrame({'id': ['A', 'B'], 'text': [ '私は ラーメン 愛する 中でも 味噌 ラーメン 一番 好き', '私は 焼きそば 好き しかし ラーメン もっと 好き']}) # TF-IDFの計算 tfidf_vectorizer = TfidfVectorizer(use_idf=True,lowercase=False) # 文章内の全単語のTfidf値を取得 tfidf_matrix = tfidf_vectorizer.fit_transform(df['text']) # index 順の単語リスト terms = tfidf_vectorizer.get_feature_names() # 単語毎のtfidf値配列:TF-IDF 行列 (numpy の ndarray 形式で取得される) # 1つ目の文書に対する、各単語のベクトル値 # 2つ目の文書に対する、各単語のベクトル値 # ・・・ # が取得できる(文書の数 * 全単語数)の配列になる。(toarray()で密行列に変換) tfidfs = tfidf_matrix.toarray()
各値を確認してみます。
print(terms) -> ['しかし', 'もっと', 'ラーメン', '一番', '中でも', '味噌', '好き', '愛する', '焼きそば', '私は']
print(tfidfs) ->[0 0 0.5364 0.3769 0.3769 0.3769 0.2682 0.3769 0 0.2682 ] ->[0.4069 0.4069 0.2895 0 0 0 0.5791 0 0.4069 0.2895 ]
これを表にまとめると下記のようになります。(小数第3位で切り捨てています)
- | しかし | もっと | ラーメン | 一番 | 中でも | 味噌 | 好き | 愛する | 焼きそば | 私は |
---|---|---|---|---|---|---|---|---|---|---|
A | 0 | 0 | 0.53 | 0.37 | 0.37 | 0.37 | 0.26 | 0.37 | 0 | 0.26 |
B | 0.40 | 0.40 | 0.28 | 0 | 0 | 0 | 0.57 | 0 | 0.40 | 0.28 |
この値は、各単語をTF-IDFによりベクトル値として数値変換した結果になっています。(TfidfVectorizerは正規化までしてくれるので、前半で述べた計算結果と若干異なっています)
この数値が大きければ大きいほど、その文書における重要単語ということになります。
TfidfVectorizerの使い方については、公式ドキュメントをご参照ください。 正規化についてはここに記載があります。