tf-idf

#tf-idf
tf-idfとはある文書中に含まれる単語の重要度を評価する手法の1つである。tf-idfはtfとidfの二つの指標を持って計算する。まず二つを分けて説明する。

##tf
tfとはterm frequencyの略であり、ある単語$w_j$が文章$d_i$に出現する頻度である。つまり、単語$w_j$が文章$d_i$に出現する回数を文章$d_i$の総単語数で割ったものである。単語$w_j$が文章$d_i$に出現する回数を関数$f(d_i, w_j)$で求められるとすると、tfは以下のように書ける。
$$
tf = \frac{f(d_i, w_j)}{\sum_{k\in d_i}f(d_i, w_k)}
$$
pythonでtfを実装すると以下のようなプログラムになる。

``` python
import MeCab

mecab = MeCab.Tagger("-Owakati")

# 文章
doc = "国境の長いトンネルを抜けると雪国であった。夜の底が白くなった。信号所に汽車が止まった。"
# 単語
word = "雪国"

# 文章を分かち書きし、単語リストに変換する。
doc_wakati_list = mecab.parse(doc).split()

# 文章の単語数
word_count = len(doc_wakati_list)
# 単語の出現数
word_emergency_count = doc_wakati_list.count(word)

# tfを求め出力 単語の出現数/文章の単語数
print('tf', word_emergency_count/word_count)
```
このプログラムは文章が「国境の長いトンネルを抜けると雪国であった。夜の底が白くなった。信号所に汽車が止まった。」、単語が「雪国」で実装したものである。

##idf
idfとはinverse document frequencyの略であり、全文章中に単語$w_j$が含まれる確率の逆数の対数(底2)をとったものである(逆文章頻度)。idfは言い換えると、文章中に単語$w_j$があるという事象の情報量である。全文章数を$N$、全文章のうち単語$w_j$が含まれる文章数を$g(w_j)$とすると、単語$w_j$のidfは以下のように書ける
$$
idf_j = \log_2(\frac{N}{g(w_j)})
$$
この式からidfは文章中に単語が出てくる回数が少なければ少ない単語ほど値が大きくなることがわかる(idfが情報量を表していると言っているから当然だけど)。
pythonでidfを実装すると以下のようなプログラムになる。

```python
import numpy as np
import MeCab

mecab = MeCab.Tagger("-Owakati")

# 文章
doc_list = ["国境の長いトンネルを抜けると雪国であった。夜の底が白くなった。信号所に汽車が止まった。",
            "道がつづら折りになって、いよいよ天城峠に近づいたと思う頃、雨足が杉の密林を白く染めながら、すさまじい早さで麓から私を追ってきた。",
            "えたいの知れない不吉な塊が私の心を始終圧えつけていた。焦燥と云おうか、嫌悪と云おうか― 酒を飲んだあとに宿酔があるように、酒を毎日飲んでいると宿酔に相当した時期がやって来る。"]
# 単語
word = "雪国"

# 文章の単語数
word_count = 0
# 単語の出現数
word_emergency_count = 0

# 文章ごとに計算する
for doc in doc_list:
    doc_wakati_list = mecab.parse(doc).split()
    word_count += len(doc_wakati_list)
    word_emergency_count += doc_wakati_list.count(word)

# tfを求め出力 単語の出現数/文章の単語数
print('idf', np.log2(word_count/(word_emergency_count+1)))
```
このプログラムは文章が「国境の長いトンネルを抜けると雪国であった。夜の底が白くなった。信号所に汽車が止まった。」などのいくつかの文章群、単語が「雪国」で実装したものである。説明なく$\log_2$の分母に+1しているが、これは単語が全文章中にない時に分母が0になることを防ぐためによく使われる手法である。

## 合体
tf-idfはtfとidfをかけ合わせたものである。
$$
　\mathrm{tf-idf}(d_i,w_j) = \mathrm{tf}(d_i, w_j) \times \mathrm{idf}(w_j)
$$
tf-idfは文章$d_i$中に単語$w_j$が出現する頻度が高ければ高いほど大きくなり(tf)、全文章中に単語$w_j$が出現する頻度が低ければ低いほど小さくなる(idf)。td-idfは単語が注目している文章中に出現する頻度に文章全体でのその単語の情報量で重み付けしたものとも考えられる。
pythonでtf-idfを実装すると以下のようなプログラムになる。

```python
import numpy as np
import MeCab

mecab = MeCab.Tagger("-Owakati")

# 文章
doc_list = ["国境の長いトンネルを抜けると雪国であった。夜の底が白くなった。信号所に汽車が止まった。",
            "道がつづら折りになって、いよいよ天城峠に近づいたと思う頃、雨足が杉の密林を白く染めながら、すさまじい早さで麓から私を追ってきた。",
            "えたいの知れない不吉な塊が私の心を始終圧えつけていた。焦燥と云おうか、嫌悪と云おうか― 酒を飲んだあとに宿酔があるように、酒を毎日飲んでいると宿酔に相当した時期がやって来る。"]
# 対象の文章
doc_tar_idx = 0
# 単語
word = "雪国"

# 文章の単語数
all_word_count = 0
# 単語の出現数
all_word_emergency_count = 0

for i, doc in enumerate(doc_list):
    doc_wakati_list = mecab.parse(doc).split()
    word_count = len(doc_wakati_list)
    all_word_count += word_count
    word_emergency_count = doc_wakati_list.count(word)
    all_word_emergency_count += word_emergency_count
    if i == doc_tar_idx:
        tf = word_emergency_count / word_count

idf = np.log2(all_word_count/(all_word_emergency_count+1))

# tfを求め出力 単語の出現数/文章の単語数
print('tf-idf', tf*idf)
```
このプログラムは先ほど同様に文章が「国境の長いトンネルを抜けると雪国であった。夜の底が白くなった。信号所に汽車が止まった。」などの文章群、単語が「雪国」で実装したものである。