文書分類などにおいて、文書の特徴量として使われる古典的な指標にTF-IDFがあります。TF-IDFは文書だけでなく、様々なデータに適用できてシンプルだけど非常に使いやすい特徴量です。
この記事では
- TF-IDFの計算式
- TF-IDFのPython実装
について紹介します。コードはJupyter Notebook形式で配布しますので、是非手元で試してみてくださいね。
TF-IDFとは
IF-IDFとは、文書内の単語の重要度(重み)を示す手法の一つです。各データが文書で、その特徴が単語になっているときを考えます。このとき特徴量として選べるのは、単語の出現回数かこのTF-IDFになります。
さて、重要度の大きい単語は、その文書の特徴語として扱うことができます。逆に、重要度が小さい単語は、その文書内ではクラス分類などに大きな影響を及ぼさないものだと考える事ができます。
TF-IDFはTFとIDFという二つの指標をかけ合わせた値です。それぞれの計算方法を見てみましょう。
TF
TFは「単語の出現頻度」を表します。これは単語の出現回数をその文書内にある単語の総合計数で割っただけの簡単な指標です。この値が大きいと重要で、小さいとそんなに重要ではないと考えることができます。
IDF
IDFは「逆文書頻度」と言います。これはthisやis、a、amなどのような、一般語(どんな文書にも出てくるような単語)のフィルタとして機能します。IDF値が高いと重要で、小さいとそんなに重要ではないと考えることができます。
式をみてください。IDFが小さいということは、df(t)の値が大きいということですね。つまりいろんな文書に出てくるよく見る単語はそこまで重要ではないと評価していることになります。
IF-IDF
TF-IDFは上記のTFとIDFをかけ合わせただけの指標です。この値が大きいと重要で、小さいと重要ではないと見ることができます。カウントベースで文書クラスタリングを行った場合、thisやisのような一般語は出現回数が多いので結果に大きく影響を与える可能性があります。
ですがTF-IDFを使った場合はどうなるでしょうか。その場合は、一般語はIF-IDF値が小さいのでそこまで影響を与えません。そして逆に、それ以外のTF-IDFが大きかった値が文書クラスタリングに大きな影響を与える可能性が出てくると言うことになります。
Python実装
IF-IDFのナイーブなアルゴリズムは上記の通りですが、同じコンセプトで少し違う数式のものが多数あります。今回は上記のアルゴリズムをシンプルにPythonだけで実装してみました。
文字列を用意
まずは文字列を用意して単語ごとに分割します。
from math import log import pandas as pd docs = [ ["犬", "可愛い", "犬", "大きい"], ["猫", "小さい", "猫", "可愛い", "可愛い"], ["虫", "小さい", "可愛くない"] ] words = list(set(w for doc in docs for w in doc)) words.sort() words
Out:
['可愛い', '可愛くない', '大きい', '小さい', '犬', '猫', '虫']
TF-IDFの実装
TF-IDFの実装は以下の通り、数式通りです。
N = len(docs) def tf(t, d): return d.count(t)/len(d) def idf(t): df = 0 for doc in docs: df += t in doc return log(N/df)+1 def tfidf(t, d): return tf(t,d)* idf(t)
これを使って先程のデータのTF-IDF値を計算してみます。
まずはTF。
result = [] for i in range(N): result.append([]) d = docs[i] for j in range(len(words)): t = words[j] result[-1].append(tf(t,d)) tf_ = pd.DataFrame(result, columns=words) tf_
result = [] for j in range(len(words)): t = words[j] result.append(idf(t)) idf_ = pd.DataFrame(result, index=words, columns=["IDF"]) idf_
result = [] for i in range(N): result.append([]) d = docs[i] for j in range(len(words)): t = words[j] result[-1].append(tfidf(t,d)) tfidf_ = pd.DataFrame(result, columns=words) tfidf_
Out:
可愛い | 可愛くない | 大きい | 小さい | 犬 | 猫 | 虫 | |
---|---|---|---|---|---|---|---|
0 | 0.351366 | 0.000000 | 0.524653 | 0.000000 | 1.049306 | 0.000000 | 0.000000 |
1 | 0.562186 | 0.000000 | 0.000000 | 0.281093 | 0.000000 | 0.839445 | 0.000000 |
2 | 0.000000 | 0.699537 | 0.000000 | 0.468488 | 0.000000 | 0.000000 | 0.699537 |
TFの値、IDFの値、TF-IDFの値を表示するセルを実際に動かして値を確かめてください。前のセクションで紹介したコンセプト通りの結果が出ていることがわかると思います。また、実際にTF-IDFを使うときは、sklearnなら tfidfvectorizer、gensimならmodels.tfidfmodelのような実装済みのクラスを使いましょう。
その方が速くて確実です。
もっと勉強するには
TF-IDF以外にも、データの種類や目的によって様々な特徴量があります。データ解析において、適切な特徴量を選ぶというのは非常に重要な要素になります。どんなデータにどんな特徴量を使うかなど、実践的なデータ解析の勉強をしたいならば、kaggleなどのコンペティションに参加しながら実戦経験を積むのが一番だと思います。
また、侍エンジニアのマン・ツー・マンでデータ解析の手法を学ぶのもおすすめので、是非考えてみてください。
まとめ
この記事では、TF-IDFについてまとめました。TF-IDFで文書データを表現してk-meansなどでクラスタリングを行ったりと、様々な機械学習モデルの入力データとして使うことができるので、是非覚えて使ってみてくださいね。