Pythonのnltkライブラリを使ってでゼロからTF-IDFモデルを実装する方法

スポンサーリンク

TF-IDFモデルとは、単語を数値で表現する手法です。

“Hello there, how have you been?” と聞けば、何を聞きたいのかすぐに分かりますが、コンピュータは数字が得意で、言葉は苦手です。

コンピュータに文章や言葉の意味を理解させるために、文脈や意味を保ちながら文章を数値で表現します。

TF-IDFモデルもその一つで、単語を数値で表現する方法です。

TF-IDFは、「Term Frequency – Inverse Document Frequency」の略で、日本語では「項頻度-逆文書頻度」と訳される。

この方法は、Bag of Wordモデルの欠点を解消している。

すべての単語に同じ値を割り当てるわけではないので、数回しか出現しない重要な単語は高い重みが割り当てられることになる。

この記事では、いくつかのサンプルテキスト・コーパスのTF-IDF表現をゼロから順を追って作成することにします。

スポンサーリンク

TF-IDFの紹介

TF-IDFとは、Term FrequencyとInverse Document Frequencyの積です。

TF-IDFの計算式は以下の通りです。

TF-IDF = 用語頻度 (TF) * 逆文書頻度 (IDF)` です。

用語頻度と逆文書頻度とは何かと聞かれたら、実際にどんなものか見てみましょう。

用語の頻度とは?

文書に含まれる単語の頻度を表す指標です。

文書中の単語の総数と比較して、その単語が文書中に出現する回数の比率です。

tf(t,d) = d中のtの数 / d中の単語の数`。

逆文書頻度とは何ですか?

コーパスにほとんど出現しない単語は、IDFスコアが高い。

これは、文書数とその単語を含む文書数の比の対数です。

コーパスが大きくなるとIDFの値が大きくなり、爆発的に増加することがあるので、この比率の対数をとることでこの影響を緩和しているのです。

0で割り切れないので、分母に1を加えて平滑化します。

IDF(t) = log(N/(df + 1))` となります。

TF-IDFモデルのステップバイステップの実装

それでは早速、PythonでTF-IDFモデルを実装してみましょう。

1. データの前処理

まずテキストデータの前処理として、学習データに含まれる単語を語彙集合にし、その集合の各単語に一意のインデックスを付与します。

#Importing required module
import numpy as np
from nltk.tokenize import  word_tokenize
 
#Example text corpus for our tutorial
text = ['Topic sentences are similar to mini thesis statements.
        Like a thesis statement, a topic sentence has a specific
        main point. Whereas the thesis is the main point of the essay',
        'the topic sentence is the main point of the paragraph.
        Like the thesis statement, a topic sentence has a unifying function.
        But a thesis statement or topic sentence alone doesn’t guarantee unity.',
        'An essay is unified if all the paragraphs relate to the thesis,
        whereas a paragraph is unified if all the sentences relate to the topic sentence.']
 
#Preprocessing the text data
sentences = []
word_set = []
 
for sent in text:
    x = [i.lower() for  i in word_tokenize(sent) if i.isalpha()]
    sentences.append(x)
    for word in x:
        if word not in word_set:
            word_set.append(word)
 
#Set of vocab
word_set = set(word_set)
#Total documents in our corpus
total_documents = len(sentences)
 
#Creating an index for each word in our vocab.
index_dict = {} #Dictionary to store index for each word
i = 0
for word in word_set:
    index_dict[word] = i
    i += 1

2. カウントを保持するための辞書を作成する

次に、与えられた単語を含む文書の数をカウントするための辞書を作成します。

#Create a count dictionary
 
def count_dict(sentences):
    word_count = {}
    for word in word_set:
        word_count[word] = 0
        for sent in sentences:
            if word in sent:
                word_count[word] += 1
    return word_count
 
word_count = count_dict(sentences)

3. タームフリークエンシーの計算関数を定義する

では、まず用語頻度(TF)をカウントする関数を定義してみましょう。

#Term Frequency
def termfreq(document, word):
    N = len(document)
    occurance = len([token for token in document if token == word])
    return occurance/N

4. 逆文書頻度を計算する関数を定義する

項頻度関数が設定されたので、次に逆文書頻度(IDF)関数を定義してみましょう。

#Inverse Document Frequency
 
def inverse_doc_freq(word):
    try:
        word_occurance = word_count[word] + 1
    except:
        word_occurance = 1
    return np.log(total_documents/word_occurance)

5. TF-IDF関数の組み合わせ

上記のTF関数とIDF関数を組み合わせて、TF-IDFモデルの出力を得るための関数を作ってみましょう。

def tf_idf(sentence):
    tf_idf_vec = np.zeros((len(word_set),))
    for word in sentence:
        tf = termfreq(sentence,word)
        idf = inverse_doc_freq(word)
         
        value = tf*idf
        tf_idf_vec[index_dict[word]] = value
    return tf_idf_vec

6. TF-IDFモデルをテキストに適用する

PythonでのTF-IDFモデルの実装は完了です。

では、テキストコーパスを関数に渡して、出力ベクトルがどのようになるかを見てみましょう。

#TF-IDF Encoded text corpus
vectors = []
for sent in sentences:
    vec = tf_idf(sent)
    vectors.append(vec)
 
print(vectors[0])
TF-IDF Model Encoded Vector
TF-IDF Encoded Vector

ここで、モデルがボキャブラリー以外の未知の単語に遭遇した場合、未知のトークンを考慮していないため、Keyエラーとなります。

この記事の目的は、TF-IDFが実際にどのように動作しているかを示すことです。

このチュートリアルのためのノートブックは、私のGitHubリポジトリにあります。

新しいテキストコーパスを用いて、自由にコードを実装・修正してください。

まとめ

今回は、PythonでTF-IDFモデルをゼロから実装してみました。

また、モデルの背後にあるいくつかの理論を理解することに焦点を当て、最終的に私たちが作成した関数を使用して独自の文章をエンコードしました。

タイトルとURLをコピーしました