Kaggle Python Tutorial Exercise: Loops and List Comprehensions

https://www.kaggle.com/learn/python

の４つめ
Loops and List Comprehensions
の最後の問題。

kaggleのdiscordで質問があったので作ってみた。


##通常
```python:MonteCarlo.py
import random

def play_slot_machine():
    r = random.random()
    if r < .005:
        return 100
    elif r < .05:
        return 5
    elif r < .25:
        return 1.5
    else:
        return 0

def estimate_average_slot_payout(n_runs):
    """Run the slot machine n_runs times and return the average net profit per run.
    Example calls (note that return value is nondeterministic!):
    >>> estimate_average_slot_payout(1)
    -1
    >>> estimate_average_slot_payout(1)
    0.5
    """
    r = [play_slot_machine() for _ in range(n_runs)]
    return (sum(r) - n_runs) / n_runs

# print(estimate_average_slot_payout(1000000))
# 0.021952

import matplotlib.pyplot as plt
import numpy as np

scale = np.linspace(100,1e6,100)
values = [estimate_average_slot_payout(int(i)) for i in scale]

coef = np.polyfit(scale,values,1)
poly1d_fn = np.poly1d(coef) 

fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(1, 1, 1)

ax.plot(scale,values, '-b', scale, poly1d_fn(scale), '--k')
ax.axhline(y=.025,xmin=.05,c='red')

ax.ticklabel_format(style='plain',axis='x')
```
![graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130729/57f54e28-3cca-ad28-be21-f9bf0ddd2bfb.png)

期待値である`0.025`に収縮していくのがわかる。

##高速バージョン

```python:faster_plotting.py
import random

# Analytic solution for expected payout =
# .005 * 100 + (.05 - .005) * 5 + (.25 - .05) * 1.5

def play_slot_machine():
    r = random.random()
    if r < .005:
        return 100
    elif r < .05:
        return 5
    elif r < .25:
        return 1.5
    else:
        return 0


import numpy as np
import matplotlib.pyplot as plt

def play_slot_machine(playingcount:int) -> np.ndarray:
    return np.random.choice([100,5,1.5,0],playingcount,p=[.005, .045, .2 , 0.75]) - np.ones(playingcount)

def expected_values(num:int) -> float:
    return play_slot_machine(num).sum() / num

def ploting(num):
    x = np.linspace(100,num,100,dtype=int)
    y = [expected_values(i) for i in x]


    fig = plt.figure(figsize=(10,10))
    ax = fig.add_subplot(1, 1, 1)
    
    ax.plot(x,y)
    ax.set_title('Expected Value 0.025')
    ax.ticklabel_format(style='plain',axis='x')
    ax.axhline(y=.025,xmin=.05,c='red')

    return

ploting(1000000)
```

![graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130729/6dcfad32-3b8f-5f23-d8f6-5abb103ae5b1.png)

`np.random.choice`で確率に応じて値が抽出できるなと思って作ってみた。（ずっと確率計算でミスをしていて収縮する値が違っていました:sweat:）

yのところはもう少し速くできそう。

# みやすく
```python:goodlooking.py
import numpy as np
import matplotlib.pyplot as plt

def play_slot_machine(playingcount:int) -> np.ndarray:
    return np.random.choice([100,5,1.5,0],playingcount,p=[.005, .045, .2 , 0.75]) - np.ones(playingcount)

def expected_values(num:int) -> float:
    return play_slot_machine(num).sum() / num

def ploting(num):
    x = np.linspace(10000,num,100,dtype=int)
    y = [expected_values(i) for i in x]

    fig = plt.figure(figsize=(10,10))
    ax = fig.add_subplot(1, 1, 1)
    
    ax.plot(x,y)
    ax.set_title('Expected Value 0.025')
    ax.ticklabel_format(style='plain',axis='x')
    ax.plot(x,[.025]*100,'r--')


    return

ploting(4e7)
```

![graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130729/5a42ff04-e2b0-3b34-d339-89942ab8f9b3.png)

最初のばらつきが大きいところをカットしたもの。かなりわかりやすくなった。
期待値のラインも`plt.plot`に変えている。

せっかく作ったので記念書き込み。