テキストマイニング
こんにちは。前回は特徴語をどのようにビジュアル表現するかについてまとめました。今回はTF-IDFの値を計算して、Word Cloudをつくるプログラムを紹介します。言語はPythonです。
プログラムをつくる上での制約
ここで、プログラムをつくるにあたり結構面倒な制約を付けました。関数、クラスといった便利なものを使わないという制約です。
その理由は、前段として行っているプログラミングの授業と関係しています。授業では生徒がプログラミングを経験してもらう際に、初心者向け学習サイトのProgateを使いました。中学校・高校向けのプランでは2つのコースまで選択できます。勤務校の授業ではPythonのコースを利用し、Python IIまでを全員が経験する課題としました。
ここまでに出てくる文法事項は、
- 変数
- 数値と文字列
- if、elif、else
- ブール演算 and、or、not
- リスト
- 辞書
- リストと辞書に対するfor
- while
- breakとcontinue
以上です。詳しい内容はProgateのサイトを参照してください。
とはいえ、形態素解析などのモジュール呼び出しやら、メソッドの呼び出しやらは、しれっと混ぜ込んでいます。これだけの文法事項で、次の内容として機械学習に挑んでいくという、なかなかの野望を持っています。
もう1つの制約は、scikit-learnなどのモジュールは使わず、「高校でTF-IDF(1)(2)」で紹介したとおりのアルゴリズムをプログラムとして記述することです。実用性を考えたらモジュールを使った方が良いと思います。しかし、授業で手計算でTF-IDFを求めているのだから、単語の数に基づいて求めるアルゴリズムがプログラムに表出させることを優先しました。それにより、該当行だけでもプログラムとの対応を確認できるようにしました。
整理すると次の2点が制約です。
- 文法事項は、基本的にプログラミング学習サイトProgateのコースPython IとPython IIの範囲内
- 手計算と同じアルゴリズムをプログラム中に記述する
授業で配布したプログラム
上に挙げた制約のため、プログラムは汚いのですが、生徒に配布したプログラムを紹介します。(実はプログラムが汚い理由がもう1つあります。はじめはナイーブベイズ分類器も同じプログラムに入れていました。実行速度の問題があり、TF-IDFとWord Cloud、ナイーブベイズ分類器に分けました。そのため、ナイーブベイズ分類器用の変数が残ってしまいプログラムが汚くなっています。)
プログラム中で、標準ライブラリでないライブラリとしてjanome、wordcloud、openpyxlを使用します。インストールされていない場合には、pipコマンドでインストールしてください。また、フォントに”KozGoPro-Light.otf”を指定しています。このフォントがなければ、代替となるフォントをotf形式またはttf形式のファイルを指定する必要があります。
files = { 'いちご' : 'ichigo.txt' , 'りんご' : 'ringo.txt' , 'キウイ' : 'kiwi.txt' }
documents = { }
for category in files:
filename = files[category]
file = open( filename , 'r' )
text = file.read()
documents[category] = text
file.close()
for category in documents:
print('【' + category + '】')
print( documents[category] )
word_list = { }
tf = { }
word_documents = { }
count_documents = { }
count_all = 0
from janome.tokenizer import Tokenizer
t = Tokenizer()
for category in documents:
document = documents[category]
word_list[category] = { }
word_count = 0
count_documents[category] = 0
lines = document.split( '\n' )
for line in lines:
tokens = t.tokenize( line )
count_all += 1
count_documents[category] += 1
words_line = [ ]
for token in tokens:
word = token.base_form
if word == '*':
word = token.surface
partOfSpeech = token.part_of_speech.split( ',' )[0]
if partOfSpeech != '名詞' and partOfSpeech != '動詞' and partOfSpeech != '形容詞':
continue
if not word in word_list[category]:
word_list[category][word] = 0
if not word in word_documents:
word_documents[word] = 0
if not word in words_line:
words_line.append(word)
word_documents[word] += 1
word_list[category][word] += 1
word_count += 1
tf[category] = { }
for word in word_list[category]:
tf[category][word] = word_list[category][word] / word_count
from wordcloud import WordCloud
for category in documents:
fpath = 'c:\windows\Fonts\KozGoPro-Light.otf'
stop_words = [ 'てる' , 'いる' , 'なる' , 'れる' , 'する' , 'ある' ,
'こと' , 'これ' , 'さん' , 'して' , 'くれる' , 'やる' ,
'くださる' , 'そう' , 'せる' , 'した' , 'できる' ,
'それ' , 'ここ' ,
'ちゃん' , 'くん' , '' ,
'て' , 'に' , 'を' , 'は' , 'の' , 'が' , 'と' ,
'た' , 'し' , 'で' , 'ない' , 'も' , 'な' , 'い' , 'か' ,
'ので' , 'よう' ,'' ]
wordcloud = WordCloud(background_color="white" ,
font_path=fpath ,
width=1024 , height=674 , ranks_only = True ,
stopwords=set(stop_words)).generate( ','.join(word_list[category]) )
wordcloud.to_file( './' + category + '.png' )
import math
idf = { }
for word in word_documents:
idf[word] = math.log( count_all / word_documents[word] ,10 )
tfidf = { }
for category in word_list:
tfidf[category] = { }
for word in word_list[category]:
tfidf[category][word] = tf[category][word] * idf[word]
from openpyxl import Workbook
filename = "tf-idf.xlsx"
book = Workbook()
for category in word_list:
sheet = book.create_sheet(category)
sheet['A1'] = '形態素'
sheet['B1'] = 'tf'
sheet['C1'] = 'idf'
sheet['D1'] = 'tf-idf'
keys = sorted( tfidf[category].items() , key = lambda x:x[1] , reverse = True )
for i , word in enumerate(keys):
sheet.cell(row=i+2,column=1).value = word[0]
sheet.cell(row=i+2,column=2).value = tf[category][word[0]]
sheet.cell(row=i+2,column=3).value = idf[word[0]]
sheet.cell(row=i+2,column=4).value = tfidf[category][word[0]]
book.save('tf-idf.xlsx')
プログラムが長いので、次から数回に分けて解説します。本文は短いですが今回はこれでおしまいにします。それではまた。
ディスカッション
コメント一覧
まだ、コメントがありません