2014年10月17日金曜日

Twitter APIとjNLPによる評判分析




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$date
awkは本当にこういうとき便利ですね。


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行未満で実装出来ます。
色々なライブラリに依存するので、以上のコードをコピペしても動かないとは思いますが、参考になるかと。


まだ有意義なデータを取り出すに至っていませんがこれから色々動かしてみようと思います。

2014年10月4日土曜日

Cocos2d-js×Webアプリ×Google App Engine

とにかくゲームを公開したい!

個人でソフトウェアプロジェクトを作る場合は様々な制約が存在します。

お金、時間、計算資源...

なるべくお金や時間をかけずに、まずはゲーム開発を練習したい。


そういう方にはCocos2d-js×Web×Google App Engineでの開発をお勧めします。
これらのプラットフォームのメリットを紹介します。


・全て無料で出来る

Cocos2d-jsはオープンソース、GAEも基本無料ですので全て無料でスタートアップが出来ます。



・公開するまでの手順が非常にお手軽

Cocos2d-jsもGAEもデプロイが非常に簡単です。
Cocos2d-jsはコマンドラインで一行、

cocos compile -p web -m release

とだけやれば、リリースビルドが出力されます。
そしてGAEからは基本的に、

config.py update ./

とだけ打てば良い訳です。
面倒な認証などはありません。


・高いクオリティのものが簡単に作れる

Cocos2d-jsはWebアプリケーションを作るに当たってのde factoのゲームエンジンです。
非常に多機能で、煩雑なコーディングをする必要がなく、コアのデザインに集中出来ます。
また、Tiledなどのマップエディタなどがあるのでゲームを広げるのも簡単に出来ます。



要するに安い・早い・簡単ということです。
試しに動かしてみたいゲームのプロトタイプを作る時などに活用してみてはいかがでしょうか。




ついでに、Cocos2d-jsの開発環境を整える所から、Google App Engineでデプロイするまででいくつかつまずいた点があったので並べます。

Points


・setup.pyを実行後はシステムを再起動する

setup.py後に再起動しなくても、cocos newで新しいプロジェクトが作れてしまう。サンプルアプリも動いてしまう。しかし、自作のプロジェクトをコンパイルしようとすると、何故か一部失敗する。どうしてかと思っていたら、システムの再起動を忘れていました。



・相対パス

Web開発の基本ですが、改めて。Cocos2d-jsの出力するhtmlは相対パスで他のファイルを指定しています。その為、ローカルではそのまま実行することが出来ません。ChromeやFire Foxなどの開発環境を使いましょう。Web開発のIDEはブラウザと連携を取るものが多いです。例えばCocos2d-jsの推すWebStormはChrome Integrationがあり、Cocos2d-jsを使うならば最も効率の良いIDEでしょう。



・app.yamlのパス

またもパスの問題です。こちらは、Google App Engineに由来する複雑さです。
GAEにデプロイするにはapp.yamlで開発環境のパスから、Web上でのパスに対応付けをしなければなりません。これがCocos2d-jsにはなかなかに厄介。出力されるフォルダはhtml5となっているでしょうから、これをまるまる指定してWeb上でのルートディレクトリとしてしまいましょう。
GAEのローカルデバッグ環境の問題点として、app.yamlの構成上ではパスは通っていないのにローカルでパスが通っている為に異なる挙動を示してしまうことがあることです。ローカルだとうまく言っていたのに、デプロイするとfile not foundとなる場合は、app.yamlのパスを確認する必要があります。




2014年9月22日月曜日

gnuplotの出力データが大きすぎる時の対処法




非常に大きなデータを扱う場合、postscriptはファイルサイズが大きくなりすぎて開くことが出来なくなってしまうことがあります。大きくなりすぎたpostscriptはデスクトップで開くことも、プリンタに出力することも、どうすることも出来なくなってしまいます。

 非常にデータ数の多いプロットは開くのにも一苦労。

こういうことがないように、gnuplotの出力はpostscriptだけでなくpng形式でも出すことをお勧めします

postscriptのデータサイズが大きくなってしまうのは、postscriptが情報をベクターデータとして保存するからです。もしgnuplotに入力したデータが1000000点あれば、1000000点とそれを構成する情報を保存しなければならない訳です。この形式の良い所は、後からこのpostscriptを解析して元データを復元しやすいところです。しかしながら、データサイズが入力データの大きさに従って大きくなっていってしまうことが問題点としてあります。

それに対してpng形式はデータを単なる画像として保存します。 ただ600*600の点に色を塗っていくだけです。この形式の利点は、元のデータがどんな大きさだろうともpngファイルの大きさは殆ど変わらないことにあります。ただし、タダの画像になるので、情報は不可逆変換されます。即ちpngファイルから元のデータを取り出すことは非常に難しいです


ので、可能な限りpostscriptで出力をして、もしデータサイズが大きくなってしまったらpngファイルに切り替えるという方法が有用でしょう。pngの復元は出来ないといっても、要は元のデータファイルを残しておけばいいのですから、それほど困ることではないです。


2014年9月21日日曜日

テキスト処理の為に学ぶべき4つの技術

テキスト処理を学ぶべき理由 

コードに限らず、テキストは常に扱う対象になります。
コードを書くことには熱心でもテキスト処理を学ぶことに熱心ではない方は結構います。
しかし、テキストはコードと同様に学ぶべき対象なのです。その理由を2点説明します。

 1. ルーチンワークからプログラミングへ

ログやデータの解析はルーチンワークではありません。

テキストとしてのデータは人間が読める対象である場合が殆どでしょう。
人間が読めるデータですから、一行ずつ直接データを読み、必要な作業を手で行うことはできます。
しかしこれはひどく退屈なルーチンワークにしかなりません。
テキストをプログラミングの対象として扱う方法や技術を学ぶことでルーチンワークを排して楽しいプログラミングをすることが出来ます

2. プログラマの生産性を向上させる

テキスト処理は手作業でやろうとすると思う以上に時間がかかるものです。
プロジェクト全体のコメントのフォーマットを変更する、などは手作業でやることも出来ますが、手作業だと変更し忘れるファイルがあったりすることは良くあります
チェックの時間も含めると手作業による効率はあまりよくないことが分かると思います。




以下で紹介する技術は全て一朝一夕で出来るものではありません。むしろ一生かけて学ぶものの一つを紹介することを目的に記事を書きました。
しかし前述のようにこれらの技術は一生使うに能う理由があります。
是非触って見てください。



1. テキストエディタ



当然ですがテキストエディタを扱うということは最も重要なことになるでしょう。

しかし、テキストエディタは熟練度による生産性の差が明瞭に表れるものの一つでしょう。
ViやEmacsなどのエディタは単純に文字を一つずつ打つという機能だけではありません。
文字列置換や様々なユーティリティがあり、また様々なショートカットキーがあります。
これらの機能は直感的ではない所が結構あったりします。それはこれらのキーが熟練者に最適であるようにデザインされているからであり、入門しやすいようになっている訳ではないからです。
この点が多くのIDEや商業ソフトウェアのUIとの違いでしょう。

入門が簡単なエディタと、熟練者にとって最適なエディタ。
一生プログラミングを続けるなら、どちらを選ぶべきかは自明でしょう。


2. awk

テキスト処理と言えばawkです。
awkはテキスト処理だけの為に開発されたという男らしいプログラミング言語です。manページも3ページしかありません。しかしテキスト処理という点に関しては不足のない言語です。

awkの基本的なアルゴリズムはパターンマッチングです。
入力テキストを行毎に読み込み、その行がパターンに合致していたら処理を行う。
これを最終行に行くまで繰り返す。

非常に簡潔で明解な言語です。文法も簡潔なので殆どの処理は一行(one liner)で済ませることが出来ます。

awk '/error/{print $1, $2}'

とすればerrorの文字列を含む行の1番目、2番目の語を出力するという処理になります。

awkは特にデータの解析に有用です。
gnuplotなどにデータを流し込む前の前処理を行ったり、統計値を取ったり、 データからデータを取り出すような処理に対して威力を発揮します。


参照リンク

The GNU Awk User's Guide
フルドキュメント。非常に詳解なので困ったらこれを見ればいいでしょう。

AWK入門(ドットインストール)
awkの入門の為ならこちらをお勧めします。awkのしっかりとした言語であるという側面と、簡単に記述できるという側面の両方を見ることが出来ます。



3. grep

grepは文字列検索の為のコマンドです。
作業のチェックやログの解析などに用いられます。

例えばプログラム中に埋め込んだTODO:をすべて読み込むには

grep -n TODO: main.cpp

とすれば

118:        // TODO: Array of dynamic sized objects.
124:        // TODO: temporal buffer to store nodes from income buffer.
147:            // TODO: Get nodes from income buffer and put it into open list.
170:            // TODO: minf(int f):
221:            // TODO: incumbent solution.
223:                // TODO: For some reason, sometimes pops broken node.
245:                //                TODO: need it to be atomic.
277:                // TODO: Push items to thread safe income buffer.
289:                // TODO: trylock
372:        // TODO: Time to printing these texts are included in the walltime.
377:        // TODO: pack to a method

のように出力され、進捗状況が概観するのに使えます。
awkと比較すると、grepは出力を編集するためのものではなく、インタラクティブに、テキストがどうなっているのかを把握するために使いやすいように思います。

grepによるパターンの検索(Oracle)


4. Ruby or Python

やや大規模なテキスト処理を行う場合、シェルスクリプトやawkでは表現力が足りなかったり、あるいは読みやすいコードにならない場合があります。しかしテキストデータに対してC++やJavaで書くのはオーバーキルな場合が多いです。

RubyやPythonのような言語を理解しているとこういうちょっとしたプログラムを実装するのにも役に立ちます。





先に述べましたように、これらの技術は小手先技ではなく、一朝一夕に得られるものではありません。しかしスケールアップしていくものです。
一生使える技術を学びましょう。




2014年9月12日金曜日

参加出来るオープンソースプロジェクトを探す3つの方法

オープンソースプロジェクトに参加することはプログラマの楽しみであり、社会貢献であり、確かな実績にもなります。

メジャーなオープンソースプロジェクト・団体の名前を上げるならば、GNU, Linux, Mozilla, Ruby, Python, Boost....毎日使っているオープンソースだけでもいくらでもあるでしょう。ただし、概してこれらのプロジェクトに貢献することは非常に大きな傾注を要します。例えばEmacsやLinuxカーネルへの参加は最も優れたプログラマしか許されず、怪しいコードを書くと袋叩きにあうなどという話があります。袋叩きは冗談としても、そのようなインパクトの非常に大きいコードを書くということは簡単に出来ることではありません。

オープンソースへの貢献が非常にハードルの高いものだと思っている方は先のLinuxカーネルの例を良く出します。しかしオープンソースというのは五万とあり、貢献の機会や方法はいくらでもあります。

しかし、五万とあるプロジェクトからどれにコミットすべきなのか、どのようなプロジェクトがあるのか分からないというのが本音でしょう。以下、そんな行き場のない熱意を持ったプログラマの為の指針を紹介します。



1. 既に使っているオープンソースに貢献する

これが出来れば万々歳ですね。使っているうちに、不便な所や、バグを発見したり、あるいは日本語のドキュメントが不足しているなぁと感じることがあると思います。

機能を足して行くタイプのプロジェクトならどんどんパッチを書いていけるし、バグの発見はそれだけで評価されることでしょう。issueに症状を書いて、こういう原因じゃないかと推測し、あわよくばパッチ案を出せれば完璧でしょう。そこまでじゃなくても、バグについて説明があるだけでプロジェクトとしては大きな前進です。

日本語化というのは重要な貢献だと思います。ローカライズというのはどのプロジェクトでも困るものです。概してローカライズの効果は非常に大きいです。英語は共通言語ですが、母国語が英語である人が殆どという訳では全くありません。プロジェクトに依りますが、ローカライズするしないで製作物の影響する範囲は全く異なります。しかし、ローカライズはその言語を母語などにしている人が必要であり、そしてそのクオリティはプロジェクトの運営者には(その人の母語でない限り)分かりません。そうするとローカライズは限られた人しか出来ず、かつ泥臭い作業だけでなく運営部分まで関わることが出来ます。そういう意味でローカライズは価値が大きいです。


2. 日本発のプロジェクトに貢献する

日本発のプロジェクトはドキュメントが英語化されていなかったりするので人の出入りが少ないことがあります。人手が少ないプロジェクトへの参加は当然ありがたがられるし、パッチを当てる機会も多いでしょう。オープンソースというと国籍は関係ない、という話はありますが、実際日本人にとっては日本のプロジェクトの方がやりやすいことは多いと思いますし、ローカライズの重要性は誰もが知っていることでしょう。
やや古いですが、日本のオープンソースという記事があります。ここから探すのも手でしょう。あと有名なのはenchant.jsでしょうか。

3. スタートアッププロジェクトに貢献する

まだ1.0に到達していないプロジェクトもあります。未完成なのでやるべきことは沢山あります。かつ、歴史が短いので参加者も少ないです。ではスタートアッププロジェクトはどうやって見つければいいのでしょうか。プロジェクトのメンバーは様々な所で宣伝して、人を集めているはずです。アンテナを高く張っていればそれを見つけることもできるでしょう。或いはGitHubで検索してみるのも手です

  star:"100..500"

のように検索すれば中規模のプロジェクトが沢山見つかります。また、GitHubは最近のコミットの頻度が表示されます。これを見れば、今まさに伸びてきているプロジェクトなのか、既に沈静化したプロジェクトなのかも判断することが出来ます。



改めて。オープンソースへの貢献=パッチのコミットと狭義に捉えるべきではないと思います。オープンソースにおける成功とは参加することである、と言います。

パッチが最も直截的な貢献のように思えますが、ドキュメントを書いたり、テストを書いたり、宣伝したり、プロジェクトを成立させる為の要素はいくらでもあります。特に職人気質なエンジニアはこういう努力をしたがらない傾向にあります。

恐らく、こういう良く見せる為の工夫というのに拘るというのはあまりアジアにある文化ではないのでしょう。そもそもオープンソースというのがアジアの文化にそぐわないものかもしれません。

泥臭い作業も重要な貢献です。それを無碍にされることはないでしょう。また、ドキュメントやテストを書くことは必ず次につながります。 パッチを書くための下準備であったり、コミュニティの雰囲気を知ったり。



とにかく何でもいいから参加する。コミュニケーションを取る。それがオープンソースにおける成功といいます。

2014年9月7日日曜日

Torqueでジョブの終了をプッシュ通知する

Torqueに大量にジョブを投げる場合、ジョブの終了を通知する仕組みがあると便利です。
しかしドキュメントが意外と少なく苦労したのでここにまとめます。

・Array Job

まず、大量にジョブを投げる場合はloopではなくarray jobを使いましょう。

#PBS -t 1-100

で100個のジョブを投げることが出来ます。

あるいは他のパラメータ同様qsubで

qsub -t 1-100 ./myJob.sh

として指定することも出来ます。

この時、myJob.shでは100個のジョブを識別するのに$PBS_ARRAYIDというパラメータが渡されます。これを用いてジョブ毎の固有の実装をすることが出来ます。


そして全てのジョブが終わった時の通知はこのArray Jobを用いて行います。


・Job Dependencies

Torqueのジョブは依存関係を指定することが出来ます。例えば、このジョブが終了してから、など。

 JOB1=`qsub ./myJob1.sh`
qsub -W depend=after:$JOB1 ./myJob2.sh

このように、qsubの返し値としてジョブIDが出るので、それを用いて依存先を指定できます。

ただし100個の仕事に依存する場合これで書くのは面倒です。そこでArray Jobを使います。

ARRAYJOB = 'qsub -t 1-100 myJobs.sh'
qsub -W depend=afterokarray:$ARRAYJOB[] ./mail.sh

・Array jobの場合はジョブの名前の後に配列を表す括弧を加える必要がありますのでご注意。

これによって、全ジョブ終了後に実行されるジョブを定義することが出来ます。
そして、その仕事としてmailを指定することでプッシュ通知が可能になります。

メールだけではなく、その場で結果の統計を取ったりしてからメールを送ることもできます。
Torqueのメール機能を使ってもいいと思いますが、自由な形式でメールを送るにはスクリプトにした方がわかりやすいと思いますので。

2014年9月6日土曜日

AI-RTS 人工知能によるリアルタイムストラテジー

Web上で簡単に人工知能を実装してモンスターと戦わせるゲームを実装中です。



まだインターフェイスやデザインを作っていないので見た目がへぼい・何が起きているのか分からん・内容が薄いですがコアとなる内部ロジックが完成したのでデプロイしました。


AI-RTS

Html5 & JavaScriptなのでInternet Explorer以外では動くと思いますが未確認です。

リアルタイムストラテジーと書きましたが、リアルタイムに戦略を考えるのは人工知能です。
コンセプトは、プレイヤーは人工知能をセットして、実際の戦闘は眺めるだけ、という感じです。
AIを書くウィンドウはこんな感じ。

http://ai-rts.appspot.com/

見た目はおいおい考えます。
言語はJavascriptです。


プレイヤーがセットしたコードはフレーム毎に呼ばれ、キャラはそれに従って攻撃したり移動したりします。

戦闘画面はこんな感じ。


......今のところデザインとかグラフィックスは適当なので何が何やら分からない感じになっています。
開発中の画面というのはこういうものです。



あと、成長要素みたいなのも取り入れて、技をアップグレードするみたいなシステムも実装予定です。


ちなみに私のPCだとデバッグ用にbombの攻撃力を100にしていたりします。



こういう類のゲームは中身よりも外見の方が大事だというのは分かっているので、デザインを誰かに頼む予定です。