あれもPython,これもPython

Pythonメモ※本サイトはアフィリエイトを利用しています

TFIDFをモジュールで計算したい(sklearn/nltk/gensimを使う)

TFIDFをパッケージでする場合、三種類の選択肢があります。
ただし、それぞれ入力や出力が違うので注意が必要です。

モジュール 入力 出力
nltk 各行、単語に分けたリスト 行、単語ごとに計算が必要
gensim 各行、単語に分けたリスト スパースマトリクス
sklearn 各行、単語をスペースで繋いだ文字列 スパースマトリクス

いったん下記データをつくります

import random

chrs = 'python'

words = []
for i in range(5):
  #1行ごとにp,y,t,h,o,nから3~10文字ランダムに選ぶ
  tmp = random.choices(chrs,k= random.randint(3,10))
  words.append(tmp)

NLTKの場合

import nltk

collection = nltk.TextCollection(words)

#語の一覧
terms = list(set(collection))

d = []
#行ごとに
for i,w in enumerate(words):
  #各語のtfidfを計算
  for term in terms:
    d.append([i,term,collection.tf_idf(term,w)])

最初につくったcollectionからtf_idfを呼び、
対象の語と文章をいれるとtfidfが計算できます。

gensimの場合

from gensim import matutils,models
from gensim import corpora 

dictionary = corpora.Dictionary(words)

#各行を順に上記のdoc2bowに渡し、それをmodel化する
corp = list(map(dictionary.doc2bow, words))
mdl = models.TfidfModel(corp)

#スパースマトリックスにする
mtx = matutils.corpus2csc(mdl[corp])

sklearnの場合

from sklearn.feature_extraction import text

# 一文字だと判定してくれない、スペースで区切りなので専用データをつくる
words = []
for i in range(5):
  tmp = map(lambda x : x + '_' ,random.choices(chrs,k= random.randint(3,10)))
  words.append(' '.join(list(tmp)))

# 一旦Bag of wordsにする
bow = text.CountVectorizer()
bow_data = bow.fit_transform(words)

#tfidfを計算する
tfidf = text.TfidfTransformer(norm=None)
#帰ってくるのはスパースマトリクス
res = tfidf.fit_transform(bow_data)

sklearnの場合はデフォルトで一文字はカウントしないつくりなので注意が必要です
また、行の中が単語のリストではなく、スペースでつながった一文(実際の英文のようなイメージ)を渡します

全体として

Python的な処理であれば、nltkの方が初心者でもやりやすいとは思います
MLのパイプラインとしては、sklearn/gensimの方が後続はつかいやすいです