SPSSで簡単テキストマイニング
SPSSはPythonと連携することが出来ます。SPSSは大変多機能ですが、業務で実際扱うデータは一筋縄にはいきません。様々な前処理が必要です。SPSSに落とし込めるよう、データの整備やクリーニングをPythonで簡単にやってしまいましょう。今回はテキストをSVMにかけるための下準備をPythonで行います。形態素解析にはMeCab-野良ビルドを用います。まずは頻度カウントしてみます
#coding:utf-8 import sys import MeCab #MeCabを呼んで使えるようにする tagger = MeCab.Tagger("-Owakati") #分かち書きをする指定 read_file = sys.argv[1] #コマンドラインから読み込むデータファイルを指定する all_text = open(read_file).read() #指定したファイルを読み込む word_list = tagger.parse(all_text).split() #読み込んだファイルを分かち書きし、生成された配列をword_listに格納 dictionary ={} #空の辞書作成 for word in word_list: #dictionaryに単語が登録されていれば頻度を+1し、登録されていなければ辞書に単語を登録し、その頻度を1とする if word in dictionary: dictionary[word] = dictionary[word] + 1 else: dictionary[word] = 1 for word, count in sorted(dictionary.items(), key = lambda x:x[1], reverse = True): #dictionaryに登録された単語を頻度降順で表示 print word + "\t -> " + str(count)
これで頻度カウントが出来ました。このデータを用いてSPSSで単語のヒストグラムを描くなどしてみるといいでしょう(SPSSお持ちの方は)。
次はテキストをSVMにかけてみましょう。SVMにかけるためには、テキストをID化しなければなりません。SVMで処理できるデータは、クラスとIDとIDの値という形式です。例"+1 :: ID1:12, ID2:4, ID3:9 ID4:4"
テキストのID化は色々なやり方がありますので、その一例を示します。「犬を連れて散歩」というテキストが与えられ、ID群が犬=ID1、猫=ID2、散歩=ID3と割り振られていた場合(そして「連れて」という単語にID振られてなければ)、「犬を連れて散歩」→「ID1:1, ID2:0, ID3:1」となります。このようなデータ形式に落とし込めるようなPythonコードを書きましょう。
#coding:utf-8 import sys import MeCab tagger = MeCab.Tagger("-Owakati") read_file = sys.argv[1] read_dictionary = sys.argv[2] #ID群が振り当てられた単語辞書 text_list = open(read_file).read().split('\n') dictionary = open(read_dictionary).read().split('\n') print ',' + ','.join(dictionary) def set_id(text): count = 0 id = [] for word in dictionary: count += 1 id.append(str(text.count(word))) return text + ',' + ','.join(id) for text in text_list: print set_id(text)
これでテキストデータをSVMに放り込めるようID化出来ます。今のはIDが事前割り振られていたという前提でしたが、実際はID辞書も自作する必要があります。面倒くさいのでそれも自動化してしまいましょう(目的に合わせて手作業した方が精度良いですが)。サンプルデータを食わせ、指定した下限値より出現頻度高い単語だけを抽出します。
#coding:utf-8 import sys import MeCab tagger = MeCab.Tagger("-Owakati") read_file = sys.argv[1] all_text = open(read_file).read() word_list = tagger.parse(all_text).split() dictionary = {} for word in word_list: if word in dictionary: dictionary[word] = dictionary[word] + 1 else: dictionary[word] = 1 #ここまでは同じ min = sys.argv[2] #頻度下限 for word, count in dictionary.items(): if int(count) >= int(min): #設定した下限以上出現した単語だけを出力 print word #出力結果をリダイレクトで取得するなど
この結果吐いたファイルを先ほどのコードの第二引数に指定します。実行するとこんな感じになります。
#ID辞書
犯罪
金
セックス
援助
交際
死
殺す
ドラッグ
シンナー
麻薬
#ID化
原文 犯罪 金 セックス 援助 交際 死 殺す ドラッグ シンナー 麻薬 援助交際してくれる人募集中〜 0 0 0 1 1 0 0 0 0 0 風邪気味なので風邪薬買いに薬局へ行ってきた 0 0 0 0 0 0 0 0 0 0 渋谷にドラッグの密売人がいるらしい 0 0 0 0 0 0 0 1 0 0 ふざけたこと言ってると殺すぞ、絶対殺す 0 0 0 0 0 0 2 0 0 0 麻薬体験ブログ公開中! 0 0 0 0 0 0 0 0 0 1
というわけで、こうやってテキストID化するとSPSSで簡単にSVMとかに放り込めて楽しいですね(SPSSお持ちの方は)。是非やってみましょう。といってもテキストデータ十分にお持ちではないケースもあると思うので、twitterからツイートを取ってくるコードも掲載しておきます。
# -*- coding: utf-8 -*- #■これは何? #twitterからパブリックなツイートを取得するツールです。 #取得する内容はツイートした時間、ツイートしたIDと名前、ツイート内容です。 #自分のアカウントとパスを書いたsetting.txtを用意して下さい #ストリーミングフローとして閲覧するだけではなく、DBファイル(tweet.db)に格納します。 #tweet.dbはPupSQLiteなどで中身を見ることが出来ます。 #https://www.eonet.ne.jp/~pup/software.html import base64 import simplejson import urllib2 import datetime import sqlite3 import os # ツイッターアカウント設定読み取り with open("setting.txt") as f: userID = f.readline().replace('\r','').replace('\n','') userPassword = f.readline().replace('\r','').replace('\n','') commitDoNum = int(f.readline().replace('\r','').replace('\n','')) #日本語のツイートだけ収集するため、ツイートが日本語かどうかチェック def is_japanese(text): def check_chr(x): return ((x >= 0x3040 and x <= 0x309f) or (x >= 0x30a0 and x <= 0x30ff)) return [ch for ch in text if check_chr(ord(ch))] #SQLite3のDB用意。既にDBファイルがある場合はそれを利用、無い場合は新規で作成する。Python2.5以上はSQLiteが組み込まれているため、通常はインストール作業不要 if os.path.exists('tweet.db'): connection = sqlite3.connect('tweet.db') cursor = connection.cursor() else: connection = sqlite3.connect('tweet.db') cursor = connection.cursor() cursor.execute("create table twitter (tweetTime text, create_dt text, user_screen_id text, user_name text, tweet text);") # Streaming APIに接続 streamingAPIURI = 'https://stream.twitter.com/1/statuses/sample.json' req = urllib2.Request(streamingAPIURI, headers={'Authorization': 'Basic %s' % (base64.encodestring('%s:%s' % (userID, userPassword))[:-1])}) streamingData = urllib2.urlopen(req) commitCnt = 0 #「commitDoNum個ツイートをinsertしたらDBにCommitする」という用途に用意したカウンタ for line in streamingData: data = simplejson.loads(line) text = data.get('text') if text and is_japanese(text): tweetTime = datetime.datetime.today() create_dt = data.get('created_at') user_screen_id = data['user']['screen_name'] user_name = data['user']['name'] try: tpl = (str(tweetTime), create_dt, user_screen_id, user_name, text) cursor.execute("insert into twitter values(?,?,?,?,?)", tpl) print str(tweetTime) + ":"+ user_name + "\n" + text + "\n" commitCnt += 1 if commitCnt == commitDoNum: #commitDoNum個ツイートをinsertしたらDBにCommitする connection.commit() commitCnt = 0 except: print "*** insert miss... ***"