今日は、Pythonでモンテカルロ法と呼ばれる、確率的な解釈を持つあらゆる問題の解決に使える非常に有名な方法を紹介します。
まずは楽しい歴史から始めましょう。
モンテカルロ史の一コマ
モンテカルロ法は、Buffon Needle Problem (https://en.wikipedia.org/wiki/Buffon%27s_needle_problem) のような複雑な数値問題を解くために使われた。
例えば、同じ幅の平行な木片でできた床があり、その上に針を落とすとします。
1940年代から使用されている。
- ロスアラモス国立研究所で核兵器プロジェクトのために中性子拡散を研究し、ENIACはM-Cシミュレーションを実行するために使用されました。
 - 水爆の開発にも使用されました。
 - 流体力学において、複雑な微分方程式(非線形放物型PDEs)を解くために使用されました。
 - 粒子の透過エネルギーを推定するため
 - 高度な信号処理とベイズ推定に使用
 - 遺伝子型突然変異選択学習機(今日のバイオインフォマティクスの初期の導入部分) など。
 
Python でモンテカルロを実装する
モンテカルロ法では、一見ランダムに見える事象をシミュレーションし、リスクを評価することができます(もちろん、他の結果も含まれます)。
これは、与えられた取引戦略のリスクを評価するために使用されています。
この記事では、カジノをシミュレートします(核兵器実験をシミュレートすることはできないので)
一般に、問題が複雑であればあるほど、より多くの擬似乱数変数が必要になります。
Google Colaboratoryを起動し、ランタイムに接続します。
1. カジノホイールの基本ロールを作成する
numpyとpandasのパッケージをインポートしましょう。
import numpy as np
import pandas as pd
 | 
- 出目は1~100の数字で、客の勝率を49~51に設定します。
 - 出目が1~50と100の場合、ハウス(/カジノ)が勝つということです。
 - 51から99の出目は、プレイヤーの勝ちです。
 
51から99の出目は、プレイヤーの勝ちとなる。
では、Pythonでシミュレーションしてみましょう。
def casino_roll():
    roll = np.random.randint(1,100)
    if roll <= 50 or roll == 100:
        print('rolled %d. you lose. House wins! Play again?!'%roll)
    elif 50 < roll < 100:
        print('you win! On a roll !')
        return True
 | 
それでは、casino_encheer_roll()を呼び出してみましょう。
4回やって、3回負けた。
2. ディーラーを作る
次に、ベットにお金を入れてみましょう。
そこで、ディーラーを作り、賭け金を受け取ってもらいます。
- 勝ったらプレイヤーに報酬を与えます。
 - 負けた場合は、そのお金をポケットに入れます。
 
def deal_bet(funds,initial_bet,bet_count):
    bet = 0
    funds_total = 0
    while bet < bet_count:
        if casino_roll():
            funds += initial_bet
        else:
            funds -= initial_bet
        bet += 1
        print('Funds : %d'%funds)
        funds_total += funds
    print('average win/loss : %f'%(10000-funds_total/bet_count))
 | 
総資金を求め、平均的な勝ち負けを求めたことに注目してください。
もしそれがプラスなら、それは勝ちです。
マイナスなら負けです。
3. 100ルピーを100回賭ける場合
つまり、これを100回実行し、毎回同じ金額100ルピーを賭けると、次のようになります。
deal_bet(10000,100,100)
 | 
x=0
while x<100:
  deal_bet(10000,100,100)
  x+=1
 | 
この負の値を得るまでに5回プログラムを実行しなければなりませんでしたが、多くの値が10000をはるかに超えているにもかかわらず、プレイヤーが全体としてお金を失っていることを観察してください。
これは、私たちが有益な取引と認識しているものが、必ずしもそうではないことを示すものです。
4. プレイヤーの数を増やす
100人に同じ賭けをさせることができる。
return (10000-funds_total/bet_count)
 | 
deal_bet() の print(funds) ステートメントをコメントアウトしてください。
これで、各プレイヤーが出した利益と損失がすべてわかるようになりました。
x=0
avg_list=[]
while x<100:
  avg_list.append(deal_bet(10000,100,100))
  x+=1
 | 
5. matplotlib を使って平均をプロットする
ここで、matplotlib を使ってデータをプロットしてみましょう。
import matplotlib.pyplot as plt
avg_list = np.array(avg_list).astype(int)
plt.figure(figsize=(20,20))
plt.plot(avg_list)plt.axhline(np.array(avg_list).mean(), color='k', linestyle='dashed', linewidth=1)
 | 
deal_bet() 関数の最後に、上記の行を追加します。
そして、修正します。

そして最後にプロットします。


まとめ
今日はこれでおしまいです。
この例でPythonのモンテカルロシミュレーションが完璧に理解できたと思います。
今度は、攻撃的なプレイヤーに対して、このようなことをしてみましょう。
例えば、勝つたびに倍額を賭けるとか。
いろいろなシナリオを考えて、自分でベット関数を変更してみてください。
それでは、また次回!