自然言語処理の基礎技術!tf-idfを簡単に解説!

文書分類などにおいて、文書の特徴量として使われる古典的な指標に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_
Out:
可愛い 可愛くない 大きい 小さい
0 0.25 0.000000 0.25 0.000000 0.5 0.0 0.000000
1 0.40 0.000000 0.00 0.200000 0.0 0.4 0.000000
2 0.00 0.333333 0.00 0.333333 0.0 0.0 0.333333
次にIDFです。
result = []
for j in range(len(words)):
    t = words[j]
    result.append(idf(t))

idf_ = pd.DataFrame(result, index=words, columns=["IDF"])
idf_
Out:
IDF
可愛い 1.405465
可愛くない 2.098612
大きい 2.098612
小さい 1.405465
2.098612
2.098612
2.098612
そしてTF-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なら tfidfvectorizergensimならmodels.tfidfmodelのような実装済みのクラスを使いましょう。

その方が速くて確実です。

もっと勉強するには

TF-IDF以外にも、データの種類や目的によって様々な特徴量があります。データ解析において、適切な特徴量を選ぶというのは非常に重要な要素になります。どんなデータにどんな特徴量を使うかなど、実践的なデータ解析の勉強をしたいならば、kaggleなどのコンペティションに参加しながら実戦経験を積むのが一番だと思います。

また、侍エンジニア塾のマン・ツー・マンでデータ解析の手法を学ぶのもおすすめので、是非考えてみてください。

まとめ

この記事では、TF-IDFについてまとめました。TF-IDFで文書データを表現してk-meansなどでクラスタリングを行ったりと、様々な機械学習モデルの入力データとして使うことができるので、是非覚えて使ってみてくださいね。

LINEで送る
Pocket

「プログラミング、右も左もわからない…」という方にオススメ

当プログラミングスクール「侍エンジニア塾」では、これまで6000人以上のエンジニアを輩出してきました。

その経験を通してプログラミング学習に成功する人は、「目的目標が明確でそれに合わせた学習プランがあること」「常に相談できる人がそばにいること」「自己解決能力が身につくこと」この3つが根付いている傾向を発見しました。

侍エンジニア塾は上記3つの成功ポイントを満たすようなサービス設計に磨きをかけております。

cta_under_bnr

「自分のスタイルや目的に合わせて学習を進めたいな」とお考えの方は、ぜひチェックしてみてください。

書いた人

フクロウ

フクロウ

第一言語はPythonです。
皆さんRustやりましょう。

おすすめコンテンツ

いまならレッスン期間が2週間延長!この秋、プログラミングを学ぼう

転職成功で受講料0円!あなたもプログラミングを学んでエンジニアデビュー