📚

Janome で TF-IDF をやってみた

2020/12/06に公開

自然言語処理のTF-IDFを試したのでまとめました。

コードはこちらになります。

理論

参考動画
https://www.youtube.com/watch?v=nsEbfO3U2pY

TF-IDFとは、Term Frequency-Inverse Document Frequencyの略。

単語の出現頻度 - 単語のレア度(正確には情報量)を指す。

TF = \frac{単語の出現回数}{全ての単語の出現回数}
IDF = \log{e}(\frac{全文書数}{その単語を含む文書数})
TF-IDF = TF * IDF

たくさん登場すれば高ポイント、レア単語なら高ポイントになるように計算がされる。

「てにをは」のように、意味がないのにどんな文章にでも頻繁に登場する単語が高く評価されたり、無駄に文章をつないで長くなった文章が高く評価されないようにする仕組み。

単語の出現回数ではなく、出現頻度(割合)にすることで、ただ長い文章がヒットしやすくなるのを回避することができる。

出現頻度(出現割合)の逆数を使うことで、出現頻度が少ないほど値が大きくなる。

正確には、出現頻度の逆数を対数変換した、情報量を使用する。

なお、情報量とはあるできごと(事象)が起きた際、それがどれほど起こりにくいかを表す尺度である。

コード

形態素解析は Janome を使用。

使用するライブラリ

import pandas as pd
import numpy as np
from janome.tokenizer import Tokenizer
from sklearn.feature_extraction.text import TfidfVectorizer

データセットは青空文庫の吾輩は猫であるの冒頭を使用。

# 元の文章 青空文庫より 吾輩は猫であるの冒頭を抜粋
sentence = "\
吾輩は猫である。名前はまだ無い。\
どこで生れたかとんと見当がつかぬ。\
何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。\
吾輩はここで始めて人間というものを見た。\
しかもあとで聞くとそれは書生という人間中で一番獰悪な種族であったそうだ。\
この書生というのは時々我々を捕つかまえて煮にて食うという話である。\
"

前処理として「。」で分割した配列を作成。

target = sentence.split("。")

文章を形態素解析をして単語同士をスペースを挟んで結合する関数を作成する。

https://knaka0209.hatenablog.com/entry/NLP_3_TF_IDF

tokenizer = Tokenizer()

def get_token(text):
    t = Tokenizer()
    tokens = t.tokenize(text)
    word = ""
    for token in tokens:
        part_of_speech = token.part_of_speech.split(",")[0]
        if part_of_speech == "名詞":
            word +=token.surface + " "
        if part_of_speech == "動詞":
            word +=token.base_form+ " "
        if part_of_speech == "形容詞":
            word +=token.base_form+ " "
        if part_of_speech == "形容動詞":
            word +=token.base_form+ " "
    return word

TF-IDF処理可能なデータセットを作成。

corpus=[]
for item in target:
    token=get_token(item)
    corpus.append(token)

print(corpus)

出力
['吾輩 猫 ',
'名前 無い ',
'どこ 生れる 見当 つく ',
'何 薄暗い する 所 ニャーニャー 泣く いた事 記憶 する いる ',
'吾輩 ここ 始める 人間 もの 見る ',
'あと 聞く それ 書生 人間 中 一番 獰悪 種族 そう ',
'書生 の 我々 捕る つかまえる 煮る 食う 話 ',
'']

scikit-learn の TF-IDF ライブラリを使用してベクトルを作成。

# TF-IDFのベクトル処理
vectorizer = TfidfVectorizer(use_idf=True)
tfidf = vectorizer.fit_transform(corpus)
 
print(tfidf.toarray())

出力
[[0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 1. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. ]
(略)
[0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. ]]

見やすいように DataFrame型に変換

import pandas as pd
display(pd.DataFrame(tfidf.toarray(), columns=vectorizer.get_feature_names(), index=corpus))

以上になります、最後までお読みいただきありがとうございました。

Discussion