名詞評価極性辞書を利用したTwitterの感情分析(Positeve/Negative判定)

Twitter感情分析所 さんを利用しようとしたら、結構重たくて、大量の処理を実行するのは申し訳ない…。と思い、じゃあ自分でコードを書いてしまえ、と思い、調べていたところ、東山昌彦, 乾健太郎, 松本裕治, 述語の選択選好性に着目した名詞評価極性の獲得, 言語処理学会第14回年次大会論文集, pp.584-587, 2008.(日本語評価極性辞書)がありました。

日本語評価極性辞書(名詞編)ver.1.0(2008年12月版)pn.csv.m3.120408.trim.gz をダウンロード→解凍し、拡張子に.txtを設定し、適当なエディタで開きます。
Python標準モジュールのcsvで読み込ませるときに、タブ区切りが上手く読み込めなかったので、\tを,に置換して、保存します(Mac OSXの場合、\はoption+\でバックスラッシュを入力)。

また、以下のサイトを参考に、Yahoo!のアプリケーションIDを取得し、形態素解析APIを利用可能にします。
PythonからYahoo!形態素解析APIを使う - 人工知能に関する断創録 | http://d.hatena.ne.jp/aidiary/20090415/1239802199

def get_tweets_from_streaming_listener(filename):は、Streaming APIで大量のつぶやきをリアルタイムに保存する方法(Python編) | inquisitor http://blog.unfindable.net/archives/4257 を参考に、tweepyからTwitter Streaming APIを利用して収集したツイートがresult01.datに保存されている場合に使える関数です。

コンソールから実行すると、スクリーンネームを聞かれますので、入力すると、そのひとのツイートと、その評価が出力されます。(※tweepyを使ってOAuth認証が必要です。)

また、毎度のことですが、Python最大の難所、PythonのUnicodeEncodeErrorを知る - HDEラボ http://lab.hde.co.jp/2008/08/pythonunicodeencodeerror.html を参考にしました。

精度がどのくらいのものなのか、P/N以外の感情も判定したい、などと色々考えていますので、コメントなど頂けると嬉しいです。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import csv
import json
import urllib
import urllib2
import tweepy
from BeautifulSoup import BeautifulSoup

# dev.twitter.comから取得してくる。
consumer_token = "********************************"
consumer_secret = "********************************"
access_token = "********************************"
access_token_secret = "********************************"

auth = tweepy.OAuthHandler(consumer_token, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
oauth_api = tweepy.API(auth)

# 名詞評価極性辞書を読み込む
in_file = csv.reader(open('pne.txt',"rb"))
pne = []
for line in in_file:
    try:
        if line[1] == 'p': score = 1.0
        elif line[1] == 'e': score = 0.5
        elif line[1] == 'n': score = 0.0
        pne.append((line[0],score))
    except: pass

# トークンのリストのP/Nを判定する。
def judge_pn(tokens):
	score = 0
	num_score = 0
	for token in tokens:
		for _pne in pne:
			if token == _pne[0]:
				score += _pne[1]
				num_score += 1
	if num_score != 0:
		pn_rate = float(score)/float(num_score)
	else: pn_rate = 0.5
	
	return pn_rate

	
# 参考:PythonからYahoo!形態素解析APIを使う - 人工知能に関する断創録 http://d.hatena.ne.jp/aidiary/20090415/1239802199
# http://developer.yahoo.co.jp/webapi/jlp/ma/v1/parse.html
appid = "********************************"  # 登録したアプリケーションID
pageurl = "http://jlp.yahooapis.jp/MAService/V1/parse"
def morph(sentence, appid=appid, results="ma", filter="9"):
    sentence = sentence.encode("utf-8")
    params = urllib.urlencode({'appid':appid, 'results':results, 'filter':filter, 'sentence':sentence})
    c = urllib2.urlopen(pageurl, params)
    soup = BeautifulSoup(c.read())
    return [str(w.surface.string) for w in soup.ma_result.word_list]

# Twitter Streaming APIを使ってfilenameにツイートが保存されているものとする
def get_tweets_from_streaming_listener(filename):
	# Streaming Listenerから読み込み
	lines = open(filename,"r")
	lines = [line for line in lines]
	tweets=[]
	for line in lines:
		try:
			tweet = json.loads(line)
			tweets.append(tweet)
		except:
			pass
	# ツイートから本文だけを取り出す
	texts = [tweet["text"] for tweet in tweets]
	
	return tweets

# tweets = get_tweets_from_streaming_listener("result01.dat")

# 個々のツイート本文をトークン化
def tokenize_list(list):
	sents = []
	for text in texts:
		tokenized_text = morph(text)
		sents.append((text, tokenized_text))
	return sents

# sents = tokenize_list(texts)

# 個々のツイート本文のP/Nを判定し、pn_ratesに格納
def pn_rates_and_sents(sents):
	pn_rates = []
	pn_rates_with_sents = []
	for sent in sents:
		pn_rate = judge_pn(sent[1])
		pn_rates.append(pn_rate)
		pn_rates_with_sents.append((sent[0], pn_rate))
	return pn_rates, pn_rates_with_sents

# pn_rates, pn_rates_with_sents = pn_rate_and_sents(sents)

# P/E/Nスコアを算出して出力する
def print_scores(pn_rates):
	p, e, n = 0.0, 0.0, 0.0
	p_num, e_num, n_num = 0.0, 0.0, 0.0
	for pn in pn_rates:
		if pn > 0.5: 
			p += pn
			p_num += 1
		elif pn == 0.5:
			e += pn
			e_num += 1
		elif pn < 0.5:
			n += pn
			n_num += 1
	sum = p_num + e_num + n_num
	
	print p, e, n, p_num, e_num, n_num
	print p_num/sum, e_num/sum, n_num/sum

if __name__ == '__main__':
	screen_name = raw_input("Enter Screen Name. > ")
	tweets = oauth_api.user_timeline(screen_name=screen_name, count=20)
	texts = [tweet.text for tweet in tweets]
	sents = tokenize_list(texts)
	pn_rates, pn_rates_with_sents = pn_rates_and_sents(sents)
	print_scores(pn_rates)
	for pn_rate_with_sent in pn_rates_with_sents:
		print "%s\t%s\n" % (pn_rate_with_sent[0], pn_rate_with_sent[1])

入門 自然言語処理

入門 自然言語処理