Twitter APIとjNLPで日本語からの評判分析を実装してみました。
システムの構成としては
1. Twitter APIでキーワードを含む直近100ツイートを取得
2. cabochaでツイートの本文を語句解析
3. 得られた語句をjNLPで評判分析
4. 統計値を取り出してプロット
5. 重要なツイートは全文出力
という感じです。
これを毎週cronで行うことでキーワードに対する評判を時系列データとしてプロットが出来るようにしました。
pythonでやればせいぜい100行程度で実装することが出来ます。
1. Twitter APIによるQuery
Pythonだととても簡単に実装出来ます。
Consumer Keyなどは自分のを入れてください。
#!/usr/bin/env python # -*- coding: utf-8 -*- # This script is to retrive search result from twitter. # Basic usage is for sentiment analysis. # This will most likely to be called from analyze.sh. # # Usage: # ./twitter.py <QUERY WORD> # # Return: # List of tweets in structure below. # <User Name> <User ID> <Text> from requests_oauthlib import OAuth1Session import json import datetime import sys # Twitter Authentication CK = '' # Consumer Key CS = '' # Consumer Secret AT = '' # Access Token AS = '' # Accesss Token Secert url = "https://api.twitter.com/1.1/search/tweets.json" # タイムライン取得用のURL # Print Date for later use #d = datetime.datetime.today() #date = '%s-%s-%d' % (d.year, d.month, d.day) word = sys.argv[1] since = sys.argv[2] params = {"q":word, "count": 100, "since_id": since} twitter = OAuth1Session(CK, CS, AT, AS) req = twitter.get(url, params = params) tweets = [] if req.status_code == 200: utftext = req.text.encode('utf-8') timeline = json.loads(utftext) statuses = timeline["statuses"] for tweet in statuses: tweetid = tweet["id"] username = tweet["user"]["name"].replace(' ', '') userid = tweet["user"]["id_str"] text = tweet["text"].replace('\n', ' ') tweet = {"tweetid": tweetid, "username": username, "userid": userid, "text": text} tweets.append(tweet) for tweet in tweets: print tweet["tweetid"], tweet["username"].encode('utf-8'), tweet["userid"].encode('utf-8'), tweet["text"].encode('utf-8') else: # エラーの場合 print ("Error: %d" % req.status_code)
2. Cabocha
Pythonで書くことも出来ましたが、簡単にbash one-linerでかけました。
cat texts$date | cabocha -f1 | awk '/名詞/{printf("%s ", $1)} /EOS/{printf("\n")}' > words$dateawkは本当にこういうとき便利ですね。
3. jNLPによる評判分析
現状、ここはかなり適当にやっています。
というかjNLPのサンプルをそのまま使っています。
cabochaによって得た名詞をそのまますべて単語単位でsentiに投げ、その総和をツイートの評判値としています。おそらくこれは良い方法ではありません。
#!/usr/bin/env python # -*- coding: utf-8 -*- import sys import codecs from jNlp.jSentiments import * sys.stdin = codecs.getreader('utf-8')(sys.stdin) sys.stdout = codecs.getwriter('utf-8')(sys.stdout) txt = sys.stdin.readlines() #print txt jp_wn = 'wnjpn-all.tab' #path to Japanese Word Net en_swn = 'senti.txt' #Path to SentiWordNet classifier = Sentiment() sentiwordnet, jpwordnet = classifier.train(en_swn, jp_wn) # Print pos & neg point for each line for line in txt: positive_sum = 0.0 negative_sum = 0.0 nouns = line.split() for noun in nouns: # print noun try: positive_score = sentiwordnet[jpwordnet[noun]][0] negative_score = sentiwordnet[jpwordnet[noun]][1] positive_sum += positive_score negative_sum += negative_score except KeyError, e: pass # print 'Not found in Dictionary.' print positive_sum, negative_sum
4. Gnuplotでプロット
ここではpos値とneg値を分けてプロットしました。
書いてて思ったのはscatter plotの方が思いました。あとで実装してみます。
ただしpos値, neg値=0.0のツイートが多いのでそれは消した方がいいかもしれません。
gnuplot<<EOF set terminal postscript enhanced color set title "Sentimental Analysis Report of $dateform: Raw Data" set xrange [0:3] set yrange [0:1] set xtics 1 set nokey set xtics ('Positive' 1, 'Negative' 2) plot '${df}pos' using (1):1 w point notitle set output "${df}$date.png" replot '${df}neg' using (1):1 w point notitle EOF
まぁこんな感じで100行未満で実装出来ます。
色々なライブラリに依存するので、以上のコードをコピペしても動かないとは思いますが、参考になるかと。
まだ有意義なデータを取り出すに至っていませんがこれから色々動かしてみようと思います。