ツイート形態素解析で幸福度調査/テキストストリーミングの話(gunicorn)
http://aisunyan.moe.hm/chiaki/emo
生活満足度調査
こんなアプリを作りました
ツイートを形態素解析して、某所にある単語のポジティブさ・ネガティブさを数値化した表と比較して、ツイートがポジティブなものかネガティブなものかを測る、というフェイクアプリです
数値の求め方とか、係り受け分析をしてないとか、いろいろ問題はあると思うんですけど、たとえば「好き」という単語を含むツイートをすると数値が上がったり、「雪」という単語で逆に数値が下がりまくったりするのを見てると、まあ面白いんじゃないかなーみたいな
ここで%になっている数値は、わかりやすいように百分率に直してあるんですけど、実はもうちょっと違う値で、無理やり%にしてるので色々おかしい、というのも課題・・・
開発の話
それより問題なのは、処理に時間がかかるので、処理状況を表示しているんですが、その間ずっとページがロード中になってしまうことなんですね・・・
こういうのやるときはwebsocketとか使ったほうが良いんだろうなあって思うんだけど、まあとりあえず成果が上がればいいやの精神でとりあえず作ってみました・・・
このアプリはflask⇔gunicorn⇔nginxという構成でLinuxで動かしているんですけど、それで、処理状況を表示するのにこういうコードを書いています
def stream_template(template_name, **context): app2 = Flask(__name__) app2.jinja_loader = FileSystemLoader('templates') app2.update_template_context(context) t = app2.jinja_env.get_template(template_name) rv = t.stream(context) rv.disable_buffering() return rv @app.route('/chiaki/emo') def main2(): if "oauth_token" not in session: auth_info = 'ログインしてください' else: auth_info = 'あなたは現在ログインしています' def generate(): if request.args.get("analyze", None) is not None: for x in analyze(): yield x else: yield ['', '', ''] rows = generate() return Response(stream_with_context(stream_template('chiaki/emo3.html', auth_info=auth_info, status=rows)))
Flask: テキスト・ストリーミングやってみた♬
このページを参考にしています
Flask(__name__)
をわざわざもう一度生成しているのは、このコードがおいてある場所がアプリのメインとなるファイルではなく、Blueprintを使って読み込んでいるため、app.jinja_env.get_template
とやってしまうと、appがflaskではなくblueprintなのでエラーになってしまうためです(説明しにくい・・・
ポイントになるのはyield
とdisable_buffering()
です。これで処理中にレスポンスを返すことができます。
しかしここで引っかかりました。テスト環境ではうまくいくのになぜか本番環境でうまくいかない
そこでこのページを見つけました
Deploying Gunicorn — Gunicorn 19.8.1 documentation
If you want to be able to handle streaming request/responses... のところ、
To turn off buffering, you only need to add proxy_buffering off;
これに従ってやるとgunicornでストリーミングとしてレスポンスを垂れ流すことができる(?)みたいです
nginxのconf
location @my_app { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Request-Id $request_id; proxy_redirect off; proxy_buffering off; proxy_pass http://hello; proxy_connect_timeout 3600; proxy_send_timeout 3600; proxy_read_timeout 3600; send_timeout 3600; }
こんなふうに設定してあります
同様の問題で困ってる方いたら参考になったら幸いです
ツイートをCSVで約400件バックアップできるサイトを作った(仮)
http://aisunyan.moe.hm/hello/tw
アプリを作りました
FlaskというPythonのフレームワークを使って作っています
改良中なんでたまにバグ起こして止まってると思いますが、できるだけサービスを維持していこうと思います
サーバー代ほしい
一応使い方
・・・といっても、2つのボタンを上から順番に押すだけです
認証するとセッションとしてoauthキーがブラウザに保存されていて、そうするとログインしている旨が表示されているはずなので、その間にcollectボタンを押してダウンロード
一応ログアウトもできます
出力されるまで少し時間がかかって、特にWebSocketとかajaxとかはいまのところ使ってないので、読み込み中状態になって気持ち悪いですが、まあ当分はこれで行こうと思います
pythonで最小二乗法 その1
このテーマはありきたりだと思うのでn番煎じという感じですが、メモとして
最小二乗法とは
ぶっちゃけよく知らないんで雑な説明はしたくないんですが、最低限の説明として、まず2次元直交座標上に表せる点データの集合があったとして、その相関を最もよく説明できる
という一次直線(y=ax+b)を求める作業ということで良いとおもいます。式が複雑になると萎えてしまうのでコンパクトなものを引用させていただきました。ありがとうございます。
もちろんこれがn次のデータになっていくとどんどんこれが複雑になっていくわけですが、それはまた今度ってことで。
こういう直線モデルの最小二乗法では、物理の実験なんかで、実験にはつきものである誤差をなるべく少なくするために使ったりするそうです。
Covというのは共分散といって、偏差の積の平均のことです。偏差ってのは平均からの差のことです。
わかりにくいと思うので簡単な例を用いて説明すると、完全に相関(?)する、xが1のときyがx*2である点を任意に3つ選び、その相関を検証します
点(1,2)、点(3,6)、点(8,16)というデータの共分散は、1,3,8の平均は4で、2,6,16の平均は8ですから、偏差の積は-3と-6の積、-1と-2の積、4と8の積というようになります。その平均は(18+2+32)/3=17.333333...と求められます。これが共分散です。あとσxはxの標準偏差です。標準偏差は求めるのが面倒くさい(手順が多いだけで難しくはありませんが)ので、適当なツールを使って求めると2.94392と出てきますので、それを使用します。これでまず求める直線の式の不明な2変数のうちの一つ、aが17.3333/(2.9439^2)で17.3333/8.6665=2.000346....と求められます。ここまでくれば切片bを求めるのは簡単で、yの平均マイナス(xの平均かける切片a)で、8-(2*4) = 0 となります。これで前提であるy=x*2(+0)が導けることがわかったとおもいます。(?)
python
まあ数学の説明は今回メインじゃないんで、この部分は読み飛ばしといても大丈夫、だとおもいます。で、ここでPythonを使っていきます。せっかくなのでさっきのデータ
点(1,2)、点(3,6)、点(8,16)
を使います。
上記の話は
import numpy as np data = [[1,2],[3,6],[8,16]] n = len(data) x = [x[0] for x in data] y = [x[1] for x in data] sigmax = np.std(x) avex = np.mean(x) avey = np.mean(y) cov = sum((x - avex)*(y - avey) / n) a = cov / sigmax ** 2 b = avey - a * avex print('傾き = ' , a) print('y軸切片 = ' , b)
と書くことができます。なお標準偏差(np.std)には不偏標準偏差というのもあるのですが、Pythonのデフォルトではそうではないそうです。あとsumは式の途中にリストがあると自動的に繰り返してくれる(?)っぽいので便利ですね。
求められました。たぶんできてるとおもいます
次回からはこれを使って実用的なことをしていきたいとおもいます。