元理系院生の新入社員がPythonとJavaで色々頑張るブログ

プログラミングや機械学習について調べた事を書いていきます

PythonによるTF-IDF

この記事に書かれていること

TF-IDFについて
PythonによるTF-IDFの実装

TF-IDFってなに?

TF-IDFはある文章(ツイートとかブログの記事等々)を特徴付ける単語を求める方法の1つで、
TF値(Term Frequency)とIDF値(Inverse Document Frequency)の積で表されます。

ツイートや文章などをこの様な尺度で表現することで、機械学習クラスタリングを行うことが出来ます。

TF値

TF値は次の式で求めることが出来ます。
 tf(i, j) = \frac{n_{i, j}}{\sum_{s\in S_{j}} n_{s, j}}

いろいろな変数が有りますね。変数は次の様に定義されています。
 i:単語
 j:文章
 n_{i, j}:文章 jに単語 iが含まれている数
 S_{j}:文章 jに含まれている全ての単語の集合

この式は、各単語 iに付いて、出現数を文章内に出現する単語の個数の総和で割っています。
沢山出現している単語程TF値は高くなります。

IDF値

IDF値は次の式で求める事が出来ます。
 idf(i) = \log \frac{N}{df(i)}

この式の変数は次のようになっています。
 i:単語
 N:全ての文章の数
 df(i):単語 iが出現する文章の数

この式は、単語についてそれぞれの文章にどの程度出現するかを求めています。それぞれの文章を見ていった際に、めったに出現しない単語は df(i)の値が小さくなり、idf値が大きくなります。めったに出てこない単語は、文章を特徴付けていると言う事です。

TF-IDF値

TF-IDF値は次の式で求めることが出来ます。
 tf_idf(i, j) = tf(i, j) \times idf(i)

この式は、TF値とIDF値の積となり、文章中に沢山出てきて、尚且つ全文章に対して珍しい単語の値が大きくなる性質が有ります。

PythonによるTF-IDFの実装

__author__ = 'emoson'


def tf(terms, document):
    """
    TF値の計算。単語リストと文章を渡す
    :param terms:
    :param document:
    :return:
    """
    tf_values = [document.count(term) for term in terms]
    return list(map(lambda x: x/sum(tf_values), tf_values))


def idf(terms, documents):
    """
    IDF値の計算。単語リストと全文章を渡す
    :param terms:
    :param documents:
    :return:
    """
    import math
    return [math.log10(len(documents)/sum([bool(term in document) for document in documents])) for term in terms]


def tf_idf(terms, documents):
    """
    TF-IDF値を計算。文章毎にTF-IDF値を計算
    :param terms:
    :param documents:
    :return:
    """
    return [[_tf*_idf for _tf, _idf in zip(tf(terms, document), idf(terms, documents))] for document in documents]

次のように実行すると、TF-IDF値を求めることが出来ます。

terms = ["リンゴ", "ゴリラ", "ラッパ"]
documents = ["リンゴ、リンゴ", "リンゴとゴリラ", "ゴリラとラッパ"]
print(tf_idf(terms, documents))

実行結果

[[0.17609125905568124, 0.0, 0.0], [0.08804562952784062, 0.08804562952784062, 0.0], [0.0, 0.08804562952784062, 0.23856062735983122]]

1つ目の文章 「リンゴ、リンゴ」に付いて、各単語のTF-IDF値は次のようになります。
リンゴ・・・0.176
ゴリラ・・・0.0
ラッパ・・・0.0

同様に、2つ目の文章 「リンゴとゴリラ」の各単語のTF-IDF値は
リンゴ・・・0.088
ゴリラ・・・0.088
ラッパ・・・0.0

3つ目の文章 「ゴリラとラッパ」の各単語のTF-IDF値は
リンゴ・・・0.0
ゴリラ・・・0.088
ラッパ・・・0.239

最もTF-IDF値が高くなる単語は3つ目の文章のラッパとなります。これはラッパが他の文章に出現していない為高くなっています。
また、リンゴとゴリラは共に2つの文章に出現していますが、リンゴは1つ目の文章に2回出現している為、1つ目のリンゴのTF-IDF値は2つ目のゴリラに対し高くなっています。