テキスト分析の大通り#09: BOWとTF-IDFの計算、SQL編
前回までで文章を単語に分解し、その結果をもとに単語の矯正を行ってきました。今回以降ではこの結果を用い、文書の判別を行っていきたいのですが、その前に大通りとしては単語評価方法としてのBOW(Bag Of Words)とTF-IDF(Term Frequency - Inverse Document Frequency)の計算を行い、そのデータを用いて行うナイーブベイズのテキスト判別という手法を通ります。
詳細な定義はネットに記載されているあまたの紹介に委ねますが、BOWとTF-IDFのTFはほぼ同じ意図の指標で、基本的には単純に文書ごとの単語発生頻度を指します。一方でIDFは文書群共通で考えた、単語の頻度の高さを低く評価します。英語でいう「the」や「a」といった頻度がどの文書でも高い単語を低く評価するような仕組みです。
今回はこのBOWとTFIDFの計算を、SQLで実装します。また次回以降で別途同じことをPythonライブラリのScikit-learnでもやってみようと思いますが、両者の結果が同じになるよう、以下に記載した幾つかの点を考慮してSQLを書いていきます。
入力データ
まず、入力用データを用意します。前回までの結果をもとに、除外対象を除外し、正規化した単語に矯正した方がいい場合は直し、のちのちナイーブベイズの学習用データとして利用するデータを用意します。文書は全部で20ありますが、このうち16までを学習用に用い、残りの4つはテスト用に残しておくことにします(絞り込みはBOW,TF-IDF計算時に実施)。並びはdocid | seqno | cat | wordで、docidが文書、seqnoが文書内におけるwordの発生順序を指します。seqno自体は後続の処理には不要です。catは結果変数で、文書が若様について記載されたものか、カスミンについて記載されたものかを示します。
TF-IDFのオプション
上記で作成したデータに対してBOWならびにTF-IDFの処理を施します。もともとTF-IDFの計算には幾つか流派というか違いがあります。TFの考え方は通常が以下の上側、Scikit-learnでは下側の計算方法です。
通常のTF=各文書における各単語の出現回数 / 各文書におけるすべての単語の出現回数
Scikit-learnのTF=各文書における各単語の出現回数、通常のTFからみると分子のみ、実質BOWと同じ
また、IDF、TF-IDFに関しても若干の違いがあります。Scikit-learnでは正規化(norm、正則化?)とスムージング(smooth_idf)に関する2つのオプションのオンオフがあり、合わせると2*2の4パターンです。両方オフにすると以下のような記述になります。デフォルトは両方オンで、その場合はどちらのオプション記載も不要です。
tfidf_vectorizer = TfidfVectorizer(norm=None, smooth_idf=False)
IDFは通常単語ごとに、合計文書数/単語が出現した文書数の対数をとります。これに対してScikit-learnのスムージングオプションでは、オフ(False)の場合は通常のIDF計算に追加で1を足し、オンの場合はもともとの割り算の分子分母両方に1を足しこみ、さらにスムージングしない場合同様追加で1を足しこみます。
通常のIDF=対数(文書数 / wordが出現する文書数)
Scikit-learnのIDF(smooth_idf=False)=対数(文書数 / wordが出現する文書数) +1
Scikit-learnのIDF(smooth_idf=True)=対数((文書数+1) / (wordが出現する文書数+1)) +1
最後にTF-IDFの計算。通常は単なるTF*IDFで求めます。Scikit-learnで正規化(norm)しない場合は上述のScikit-learn定義のTF(=BOW)とIDFのスムージングオプションに応じた値をかけて求めます。正規化する場合は、正規化していないTF-IDFの結果に対して正規化の処理を施して最終的なTF-IDFの結果とします。
計算の実施
以上のオプションを踏まえ、計算をしたのが以下のSQLです。
クエリーの構造としては単純で、最初のクエリーでBOWならびにTFの計算を、次にIDFの計算を、最後にTF-IDFの計算をしています。それぞれここまでで記載してきたパターンのすべてに対応するようにしています。ただ、過去の経験から言うと単純なBOWを利用する方がナイーブベイズの判別には向いていました。なので与えられた時間に応じてまずはBOW、時間があればScikit-learnデフォルト(normもsmooth_idfのオプションもオン)のTF-IDFを順に試して比較、それでも時間があれば他のオプションをいじくる方がいいかなと個人的には思います。一方でコサイン類似度の分析をする際のインプットにはTF-IDFを利用しますし、単純にIDFを確認して非特徴的な単語を確認することも有用であるため、TF-IDFも無駄ではないかと思います。
データを見てみましょう。データは16の文書と、その中にある単語のユニーク85文字の総当たりで、1360行作成されます。以下のSQLでピンクとバスケットボールに関する計算結果を確認します。
select * from jumbo.aud08_train
where word in ('ピンク','バスケットボール')
order by word, docid
;
今回は以上で、次回はこのデータを使ってナイーブベイズの学習、およびスコアリングを行っていきます。
(TeradataやPython、およびPythonライブラリのインストールや環境構築、辞書登録、参考にしたページ等は以下にまとめています)
///