目次
はじめに――長年の疑問
自然言語処理でテキスト分類などに、よくtf-idfが使われます(最近はそうでもないのかもしれないが)。一般には、tf-idfを使うことで分類精度の向上効果があると認識されているようです。
このことを長年疑問に思っていました。tf-idfのうち、tfは文書中の単語の出現回数(あるいは相対頻度)ですから、単なるBag of Wordsと変わりません。また、idfは文書全体でのその単語の出現する文書数の対数みたいなものですから、文書集合全体で各単語に1つのidfが定まります。
けっきょく、tfi-dfはBoWにidfの列ベクトルをかけたものとみなせそうです。ということは、とても単純な線形変換ですから、こんなもので本当に分類精度が上がるんかいな? という疑問をずっと抱いてました。分類器のアルゴリズムによってはある程度効果は期待できるかもしれないが(特に単純なものなら:k近傍法とか)、たとえば確率分布として取り扱うナイーブベイズや、線形変換をかけまくって分類できる軸を探すLDA(Linear Discriminant Analysis:線形判別分析)、あるいは決定木で分類に有効な特徴を探し出すRandomForestのような手法ではまったく効かないんじゃないの、という仮説をずっと考えていました。
せっかくなので検証してみます。
スポンサーリンク
検証
検証用のデータは、sklearnのdatasetsから使える20newsgroupsにしました。fetch_20newsgroupsで使えます。
ただし、このデータは量が多くて(1.1万件ほど)処理を回すのが大変なので、全体のだいたい40%をランダムサンプリングすることにしました。
また、min_df=0.03, max_df=0.5, stop_words="english"を指定し、予め次元数を501次元にしています。ここがスタートラインです。
このデータから4種類の方法で特徴量を作りました。
- 単語の出現回数(CountVectorizerで直接作成)
- 1をl2ノルムで割って正規化したもの
- tf-idf(TifdfVectorizerで生成。norm=Noneを指定して正規化なしの条件でやる)
- 正規化tf-idf(norm="l2"を指定)
これらに対し、以下の分類器で交差検証を回して分類スコアを計算しました。
- ナイーブベイズ(Gaussian Naive Bayes)
- k近傍法(K Nearest Neighbors)
- 線形判別分析(Linear Discriminant Analysis)
- SVM(Support Vector Machine)
- ランダムフォレスト(RandomForest Classifier)
以下に検証に使ったソースコードを載せておきます。
結果
次のような結果になりました。
分類器別に端的にまとめると、
- ナイーブベイズ:正規化効果あり。tf-idf効果なし
- k近傍:正規化、tf-idfともに効果あり
- 線形判別分析:正規化効果あり。tf-idf効果なし
- SVM:正規化効果あり。正規化なしtf-idfまったくダメ。正規化+tf-idfは効いてる可能性あり
- ランダムフォレスト:正規化、tf-idfともに恐らく効果なし。効果があるとしても1%以下
という結果になりました。要するに、
- tf-idfは基本的に無力
- tf-idfをする暇があったらl2ノルムで割る。こっちの方が効く
- ただし一番精度を出せてるRandomForestでは、l2ノルムで割る正規化すら大して効いていないので、どこまで意味があるかは正直微妙
という結論です。
tf-idfは死んだのか?
少なくとも文書分類における特徴抽出手法としては死んだ、と言って構わないでしょう。
このことは仮説の通りだったので、驚きはあまりないです。tf-idfは『分類精度を上げる目的』ではほとんど使えないというのが結論です。
ではなぜtf-idfがこれまでもてはやされてきたのか? 相対頻度への変換や正規化によって、生BoW(単語の出現回数数えただけ)より良い結果が得られてきたためではないでしょうか。肝心のidfによる重み付けは「ちっとも意味がない」と言わざるを得ないと思います。
では、tf-idfは使えない子なのか? 分類に使う特徴量としては上記の通り無意味ですが、tf-idfは特徴語抽出に使えます。tf-idf(の文書集合内の平均)が高すぎず低すぎない単語を抜き出すことで、文書の特徴をよく表す単語を抽出するという使い方です。これは教師なしで計算の軽い特徴選択手法として利用できますから、そっちでは役に立つでしょう、たぶん。
まとめ
思った通り向上しませんでした。