自然言語処理の最新手法"word2vec"で艦これ加賀さんから乳を引いてみる
概要
この記事は自然言語処理という分野の最新手法word2vec
を利用して誰でも遊べるようにするための手順を説明するものです。
word2vecを利用すると意味の計算が実現できます。
例えば"king"から"man"を引いて"woman"を足すと"queen"が出てきたり、
"東京"から"日本"を引いて"フランス"を足すと"パリ"が出てくるという面白い手法です。
自然言語処理とは人間が日常的に用いる自然言語をコンピュータに処理させ、
翻訳や要約、文字入力支援や質問応答システムを作るなどに活用されている分野です。
自然言語処理と言うと耳慣れない言葉かもしれませんが、
実は検索や推薦などで私たちが日常的に利用しているなじみ深い技術でもあります。
自然言語処理の適用範囲や要素技術は幅広いのですが、
その中でもword2vecの特色は、
冒頭でも挙げたように「意味の計算」が出来ることです。
これは今までの技術では実現し得なかったことで、
今後研究が進むにつれどんどん応用が広がっていくことでしょう。
word2vecは2013年ごろ主にMikolov達が発表したもので、
自然言語処理研究者の中でも伸びしろの大きさから
今最も注目されている新技術だと思われます(筆者主観)。
本記事ではword2vecを利用することを主眼としており、
理論的な説明は下記を参照してください。
Statistical Semantics入門の発表をしました
さて、それでは今からword2vecで遊んでみる流れを紹介します。
遊ぶ前に、何を目的としてどのようなデータを利用するかなど
問題設定をして作業の流れを把握しましょう。
■理由、応用先
好みの萌えキャラに対して好みの属性を足したり引いたりすることによって
更に萌えるキャラを推薦することが可能になるため。
従来の推薦技術では同じようなジャンルのものばかりを薦めがちであったり、
どのような推薦をして欲しいかをユーザが自由に決定できないという欠点があります。
そこでword2vecを用いることの利点として、従来の推薦技術では成し得ない
「推薦の方向」を操作可能なことが特徴であることが挙げられます。
これによってより良い萌えキャラでブヒれるようになり、
各提督が艦娘の新たな魅力に気づくことによって鎮守府に愛と平和がもたらされる。
なお、数いる艦娘の中から特に加賀さんを選んだ理由は、
艦これの乳と言えば加賀さんであるという
全宇宙の総意に基づいた必然によるものである。
反論は一切認めない、全面的に拒否する。
■インストールするもの
python2.X(3系だと下記ライブラリが動かないかも…)
mecab(辞書はshift-jis,つまりデフォルト設定で)
gensim(入れる前にscipyなども入れろと言われるかもしれません)
■作業の流れ
- テキストデータを2ちゃんねるから取得する
- 取得したテキストをword2vecで処理できるよう加工する
- word2vecでデータを利用してモデルを作成する
- word2vecのモデルを利用して加賀さんから乳を引く
1. テキストデータを2ちゃんねるから取得する
word2vecはデータから学習して意味の計算が可能なモデルを作り出します。
そのためデータを用意する必要があります。
良いデータが無いと良い学習が出来ず、意味の計算結果も直感に沿わないものとなってしまいます。
良いデータとは、出来る限り大量かつゴミを取り除いたものです。
2ちゃんねるのデータのため、大量のタグやAAなどが入っています。
それを本来なら様々な手法とかなりの手作業でクリーニングしていくのですが、
本記事は初心者向けのため最低限の処理を施したものを用意しておいたので、
それを利用して下さい。
DLしてkankore.pyと名前を付けて保存します。
使い方は
python kankore.py url 板フォルダ キーワード(スレタイに指定したキーワード含まれてるスレを取得)
って感じです。
具体的には以下のようにします。
python kankore.py http://uni.2ch.net/ gameswf/ 艦これ > kankore.txt
これで2ちゃんねるのデータを取得してkankore.txtというファイルに保存できます。
2. 取得したテキストをword2vecで処理できるよう加工する
次に、取得したデータを分かち書きします。
英語は各単語の切れ目にスペースを入れますが、
日本語は単語の切れ目を明示的に与えない表記をします。
そのため、どこからどこまでが単語なのかを明示的に与える必要があります。
各単語を空白などで切り分けた表記を分かち書きと言います。
例として、「李も桃も桃のうち」を平仮名にした文を分かち書きすると
すもももももももものうち→すもも も もも も もも の うち
という感じになります。
これも本来ならこの分かち書きするのは結構難しくて色々煩雑な作業があるのですが、
今回は私の方で用意した艦これ辞書を使います。
分かち書きにはmecabを利用します。
これは自然言語処理界隈でデファクトスタンダードなツールです。
インストール作業は簡単なのでこちらなどを見て下さい。
http://handsrecs2nd.seesaa.net/article/140090025.html
mecabをインストール出来たら、用意しておいた艦これ辞書を使います。
これをダウンロードして、mecabフォルダの下にあるdicフォルダに置きます。
mecabフォルダの下にetcフォルダがあるのでそこのmecabrcファイルを開いて
; userdic = /home/foo/bar/user.dic
と書かれた行を
userdic = "C:\(mecabインストールしたフォルダ)\dic\kankore.dic"
と書き換えます。
これで辞書の準備はOKです。
「あきつ丸改二で大発動艇もっと欲しい」という一文をmecabに食わせる場合、
辞書追加前は
>あ フィラー,*,*,*,*,*,あ,ア,ア
>きつ 形容詞,自立,*,*,形容詞・アウオ段,ガル接続,きつい,キツ,キツ
>丸 名詞,固有名詞,人名,姓,*,*,丸,マル,マル
>改 名詞,一般,*,*,*,*,改,アラタメ,アラタメ
>二 名詞,数,*,*,*,*,二,ニ,ニ
>で 助詞,格助詞,一般,*,*,*,で,デ,デ
>大 接頭詞,名詞接続,*,*,*,*,大,ダイ,ダイ
>発動 名詞,サ変接続,*,*,*,*,発動,ハツドウ,ハツドー
>艇 名詞,接尾,一般,*,*,*,艇,テイ,テイ
>もっと 副詞,一般,*,*,*,*,もっと,モット,モット
>欲しい 形容詞,自立,*,*,形容詞・イ段,基本形,欲しい,ホシイ,ホシイ
となりますが、この辞書を追加すると
>あきつ丸 名詞,一般,*,*,*,*,あきつ丸,アキツマル,アキツマル
>改二 名詞,一般,*,*,*,*,改二,,
>で 助詞,格助詞,一般,*,*,*,で,デ,デ
>大発動艇 名詞,一般,*,*,*,*,大発動艇,,
>もっと 副詞,一般,*,*,*,*,もっと,モット,モット
>欲しい 形容詞,自立,*,*,形容詞・イ段,基本形,欲しい,ホシイ,ホシイ
という感じになります。
mecabの準備が整ったらコマンドプロンプトで
mecab -Owakati kankore.txt > wakati_kankore.txt
とやると分かち書きされたファイルが生成されます。
これでようやくword2vecに流し込めます、お疲れ様でした、
真の地獄はこれからだ。
3. word2vecでデータを利用してモデルを作成する
これからgensimを利用してword2vecを実践してみます。
word2vecはgoogle版の実装があってこれ使った方が1.5倍くらい速いのですが、
*2
とりあえず動かす分にはpythonから扱える方が簡単かと思いますので
ここではgensimというライブラリを利用します。
*3
pip install gensim
でgensimをインストールすることが出来ます。
次のコードをコピペして実行して下さい。
from gensim.models import word2vec import logging logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO) # 今どれくらい処理が進んでるか確認する用 sentences = word2vec.Text8Corpus('wakati_kankore.txt') model = word2vec.Word2Vec(sentences, size=200) #MBAだと100MBで2分弱くらいかかりました def s(posi, nega=[], n=5): cnt = 1 result = model.most_similar(positive = posi, negative = nega, topn = n) print '順位', 'キャラ名', '類似度' for r in result: print cnt, r[0], r[1] cnt += 1
これで準備完了!gensimを使うととっても簡単ですね!
関数sの引数は
s([足したい属性], [引きたい属性(省略可。省略時引きたい属性無し)], 上位何個出力するか)
という感じで設定して下さい。
これで意味を計算して類似度が高い順に出力してくれます。
4. word2vecのモデルを利用して加賀さんから乳を引く
早速加賀さん…の前にちょっと霧島で試してみましょう。
霧島は戦艦のメガネ担当です。
艦これはメガネ担当が少なく、
特に霧島は主力を張れる実力かつ委員長タイプという
特異性を持った愛すべき艦娘です。
霧島と類似度が高いキャラ上位5名を上げていきましょう
>>> s(['霧島'])
>順位 キャラ名 類似度
>1 榛名 0.845242
>2 比叡 0.807935
>3 隼鷹 0.696393
>4 鳥海 0.676646
>5 ヒエー 0.668688
1位榛名、2位比叡は姉妹艦+同じ戦艦という艦種でもあり順当。
3位の隼鷹はどういう繋がりかよくわからないですね。
4位の鳥海はメガネ繋がりではないでしょうか。
4位に鳥海が出てきたので、霧島にメガネを足して
戦艦を引いてみるとどうなるか確認します。
>>> s(['霧島','メガネ'],['戦艦'])
>順位 キャラ名 類似度
>1 鳥海 0.507391
>2 深雪 0.49015
>3 比叡 0.482907
>4 文月 0.478213
>5 榛名 0.465617
見事鳥海が1位になりました。
そして先ほどは1位で類似度も非常に高かった榛名が
5位ギリギリまで落ち込んでいるのが面白いですね。
さらに鳥海の艦種である重巡を足してみると…。
>>> s(['霧島','重巡','メガネ'],['戦艦'])
>順位 キャラ名 類似度
>1 鳥海 0.666885
>2 由良 0.635467
>3 高雄 0.62329
>4 利根 0.615573
>5 古鷹 0.61162
鳥海1位は変わらないのですが、類似度がぐっと上がりました。
由良が上がってきてるのはなぜでしょうかね?
そして榛名は完全に落ちました。
色々適当に投げて遊んでみましょう
>>>> s(['おにおこ'])
>順位 キャラ名 類似度
>1 鬼怒 0.635817
>2 荒潮 0.61133
>3 黒潮 0.604449
>4 ひえー 0.603935
>5 カカオ 0.601855
鬼怒(きぬ)はその字面から「おにおこ」
と呼ばれることが多いので狙い通り。
>>>> s(['高雄']) #艦これおっぱい担当。心の底から愛すべきキャラ
>順位 キャラ名 類似度
>1 利根 0.76036
>2 鳥海 0.736499
>3 古鷹 0.729154
>4 愛宕 0.725223
>5 那智 0.718696
>>>> s(['長良']) #艦これスポーツ女子担当。全てを捧げて愛すべきキャラ
>順位 キャラ名 類似度
>1 球磨 0.838549
>2 多摩 0.792809
>3 名取 0.78698
>4 由良 0.742747
>5 羽黒 0.723103
>>>> s(['不知火']) #艦これツン担当。言うまでも無く最も愛すべきキャラ
>順位 キャラ名 類似度
>1 霰 0.791995
>2 黒潮 0.758737
>3 満潮 0.750464
>4 霞 0.748772
>5 荒潮 0.743553
単に2ちゃんねるのテキストを食わせただけで、
艦種メタデータを与えたわけではないのですが、
大体艦種が揃ってますね*4。
ん?なんでこの艦娘を選んだかって?
そうですね、愛かな。
>>>> s(['不幸','姉妹'])
>順位 キャラ名 類似度
>1 鶴 0.691494
>2 扶桑 0.68556
>3 金剛 0.645539
>4 伊勢 0.623382
>5 妹 0.618033
史実、作中台詞、二次創作で何かと不幸に遭遇することから
不幸姉妹と呼ばれる瑞/翔鶴、扶桑。
金剛とか伊勢は不幸と言うか姉妹が強く利いてきたのかなって感じですね。
>>>> s(['提督'])
>順位 キャラ名 類似度
>1 諸氏 0.472251
>2 紳士 0.451628
>3 変態 0.438056
>4 ブルネイ 0.430615
>5 新米 0.428584
提督同士で呼びかける時よく「提督諸氏」って使うからっぽいですね。
あと3位に変態が来てるんですが皆さんの言動を見るに
これが1位であるべきだと思いましたまる。
もっと良いモデルを作ればきっと一位になるでしょう。
さぁお待ちかね、加賀さんです。
>>>> s(['加賀'])
>順位 キャラ名 類似度
>1 赤城 0.813888
>2 飛龍 0.718207
>3 蒼龍 0.712446
>4 鳳翔 0.675858
>5 祥鳳 0.668783
空母が並んでてまぁ順当な感じです。
ちなみに1位の赤城が0.8超えてて、さらに2位に0.1近い大差つけてるの、
あんまり他で見たこと無いのでよほど頻出な組合せのようですね。
古来よりの言い伝えとして
「ケツの翔鶴、乳の加賀」
という名言があるのは皆さんもご存知の事と思われます。
ではその加賀さんから乳を引いてみたらどうなるでしょうか。
>>>> s(['加賀'],['乳'])
>順位 キャラ名 類似度
>1 赤城 0.492795
>2 飛龍 0.444622
>3 蒼龍 0.436392
>4 瑞鶴 0.411837
>5 Ju 0.408483
結果は、1~3位までは変わらず、4位にこれまでランク外だった瑞鶴が入りました。
1~3位までは加賀さんという属性に寄せられたもので、
そこから乳を引いた結果として寄せられた瑞鶴が
この場合加賀さんの神々しい乳の要素を取り除いた存在と解釈出来ます。
具体的に加賀さん

と瑞鶴

を見比べてみましょう。
この堅い胸当ての上からでもわかる加賀さん圧倒的な質量を誇る胸、
それに対比すると…いや、その、努力は感じる瑞鶴の胸。はい!
終わりに
なんかおもしろそー!と思って頂ければ幸いです。
word2vecはこれまで出来なかったことを可能にする技術です。
それゆえ今後どのように活用出来るだろうかワクワクがドキドキです。
ただ、まだ出たばかりの技術であるため、知見が殆ど溜まっていません。
あんまりにもデータ依存過ぎる(ちょっと前処理変えるだけで全然結果変わる)し、
結果が信用できるかと言われるとかなり微妙です。
チューニングの仕方も分からず手探りで、
ひたすらモデル作りまくってテストした結果を
目で見比べて良さそうな雰囲気のモデルを選択するという感じで動かしています。
非常にbadです。
だからこそチャンスで、今この技術を使って面白いことしたらワンチャンあるでよ。
ということで、みんなでword2vec触りまくって
「こんなこと出来るよ!」
「こんな使い方どうだろう?」
ってのをやっていければいいなーと思います。
参考文献
http://blog.unnono.net/2014/02/statistical-semantics.html
http://blog.unnono.net/2014/01/nips2013word2vec.html
http://www.slideshare.net/uchumik/rnnln
http://aclweb.org/anthology/N/N13/N13-1090.pdf *5
謝辞
ニコニコ学会で発表させて頂きました。
その場で色々コメント頂けて良かったです。
ベストLT有難う御座いました。
追記

「将来加賀さんに成長する可能性のある駆逐艦を抽出する」
というタスク、面白みあるので誰かやりましょう!!
WindowsでPython3.3科学計算用環境を整えてみ…ようとしたんですが
Python2.7から3.3に移行しました。
このタイミングで移行した理由は、Python3.xは文字コードがunicodeに統一されているとか高速化されていると言われてたので前々から移行したかったところに、SciPyなどの科学計算ライブラリが3.3でも動作するようになったと聞いたからです。
参考として以下を読みました。
2.x系と3.x系の違い
Python 3.3 が間もなくリリースされるので新機能を確認しておく
確認したところ、大体のライブラリは動いてるけど、全てが上手くいくわけではないっぽいので、今の時点で移行する必要性があるかどうかはかなり微妙です。おすすめするつもりはありません。
インストール作業
本家からPython3.3本体をダウンロードしてインストールします。
Windows用科学計算ライブラリなどのバイナリファイルは下記から落としてきます。
Unofficial Windows Binaries for Python Extension Packages
入れたもの:NumPy, SciPy, Matplotlib, pandas, Python-igraph
(残念ながら、私の環境ではNLTKはインストールは出来たものの、importの時点でこけました…。networkXに至ってはインストールすら出来ず…)
単純にexeをDLして叩けばインスコ可能です。
Pythonの様々なモジュール入れるためにpipやeasy_installを利用することが多かったと思います。
Python3.3でもそれらを利用できるようにここに従ってインスコ。
(他、pipやeasy_installを代替するpysetupが標準搭載されると聞いたのですがここ見る限り、今回は採用見送ったんですかね)
動作確認
2.7時代に作ったスクリプトをそのまま色々流して見たのですが、色んな所でこけまくります(メジャーバージョン上がってるので当然と言えば当然ですが)。
私はよくワードカウントなどするのですが、その際辞書を作ってランダムにキーを取得するなんてことをしてました*1。
d={"a":100, "b":200}
d.keys()[random.randint(0,len(d)-1)]
これが動かない。
なぜかというと、keysは2.7ではlistを返してくれたのですが、3系ではviewを返してくれるからです。
なので、同じことしたければ
d={"a":100, "b":200}
list(d.keys())[random.randint(0,len(d)-1)]
と一旦listに変換する必要があります(他何か方法があれば教えて下さい)。
また、urllibを利用する際、2.7ではimport urllib2としていたのですが、3.3で同じことすると"No module named 'urllib2'"と怒られました。
ここを見るとわかるように、urllib2さんはurllib.request, urllib.errorに変更されたそうです。
なのでfrom urllib.request import urlopenとやればOKです。
今のところ標準的なライブラリで大きくこけたのはこれくらいです。
で、追加で入れた科学計算系、特にmatplotlibは色々こけまくってます…。未だにどうすれば解決するのかわから無いモノも多く、これといった理由が無い限り、3.3に移行するのはちょっと待った方が良いかなーという感じです。ってかNLTKとNetworkX使えないの本当に痛い…。一体どうすれば…。
まとめ
2.7最高!
後日談
requestsとかBeautifulSoupとかも正常に動いてないことが判明したので2.7に戻しました…
まとめ2
2.7最高!!
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... ***"
Tokyo.SciPy#3 ガチャとは心の所作
http://partake.in/events/ac0fcc7d-a289-4e2a-bb8e-1965aab8b17b
Pythonの数値計算系モジュールNumpyを用いてガチャコンプに関する正しい確率認識をしましょうというスライドを作りました。
ソースを置いておきます。宜しければご覧下さい。
import numpy as np import pylab as plt def gachaMain(weight, trialNum): length = len(weight) sumWeight = sum(weight) return [gachaDo(weight, length, sumWeight) for i in range(trialNum)] def gachaDo(weight, length, sumWeight): cnt = 0 gachaCompStatus = [0] * length while 0 in gachaCompStatus: cnt += 1 rnd = np.random.randint(sumWeight) + 1 for i in range(length + 1): if sum(weight[:i]) < rnd and rnd <= sum(weight[:i + 1]): gachaCompStatus[i] += 1 break return cnt iter = 10000 plt.subplot(221) gachaWeight = [1, 1, 1, 1, 1, 1] gachaCompData = gachaMain(gachaWeight, iter) plt.hist(gachaCompData) plt.figtext(0.35, 0.85, 'Weight = ' + str(gachaWeight)) plt.figtext(0.35, 0.83, 'mean:' + str(np.mean(gachaCompData))) plt.figtext(0.35, 0.81, 'std:' + str(np.std(gachaCompData))) plt.subplot(222) gachaWeight = [100, 50, 10, 10, 3, 1] gachaCompData = gachaMain(gachaWeight, iter) plt.hist(gachaCompData) plt.figtext(0.78, 0.85, 'Weight = ' + str(gachaWeight)) plt.figtext(0.78, 0.83, 'mean:' + str(np.mean(gachaCompData))) plt.figtext(0.78, 0.81, 'std:' + str(np.std(gachaCompData))) plt.subplot(223) gachaWeight = [5, 5, 3, 3, 2, 1]#sum weight := 19 gachaCompData = gachaMain(gachaWeight, iter) plt.hist(gachaCompData) plt.figtext(0.35, 0.4, 'Weight = ' + str(gachaWeight)) plt.figtext(0.35, 0.37, 'mean:' + str(np.mean(gachaCompData))) plt.figtext(0.35, 0.35, 'std:' + str(np.std(gachaCompData))) plt.subplot(224) gachaWeight = [10, 3, 2, 2, 1, 1]#sum weight := 19 gachaCompData = gachaMain(gachaWeight, iter) plt.hist(gachaCompData) plt.figtext(0.78, 0.4, 'Weight = ' + str(gachaWeight)) plt.figtext(0.78, 0.37, 'mean:' + str(np.mean(gachaCompData))) plt.figtext(0.78, 0.35, 'std:' + str(np.std(gachaCompData))) plt.show()