Pythonでポアソン分布と戯れる

#はじめに
統計分布と戯れたシリーズ第三段ということでポアソン分布をお届けする。

# ポアソン分布
- 書き方 Po(λ)
- 確率関数 $$ P(X=x) = \frac{λ^x}{x!}exp(-λ) $$
- 期待値 λ
- 分散 λ

#確率関数を書いてみよう
```python
def my_poisson(x, l):
    ret = (np.float_power(l, x) * np.exp(-l) / math.factorial(x)) 
    return ret
```

自前で定義した関数をそのまま使うケースは少ないだろうが、powerではなくfloat_powerを使わないと、xが大きくなった時に計算がおかしくなる。

#確率関数を描画してみよう

定義した確率関数を使って、$Po(5)$ に従うポアソン分布を描画してみる。

```python
# X～Po(5)
xs = []
ys = []
for x in range(20+1):
    xs.append(x)
    ys.append(my_poisson(x, 5))

fig = plt.figure(figsize=(8,5))    
ax = fig.add_subplot(1,1,1)
ax.bar(xs, ys)
```

こんな感じ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329816/55801df7-307e-cd78-c8b0-16b7cf649d25.png)


なお、scipyでやるとこんな感じだ。検算するとよいだろう。

```python
# Scipyの確率関数で検算する
from scipy.stats import poisson
rv = poisson(5)
ys_scipy = rv.pmf(xs)

fig = plt.figure(figsize=(8,5))    
ax = fig.add_subplot(1,1,1)
ax.bar(xs, ys_scipy)
```

#再生性を確認しよう
$ X1～Po(λ1), X2～Po(λ2) $ である時、$X1 + X2～Po(λ1+λ2)$ になることが知られている。 これをポアソン分布の再生性という。

そこで、$X1～Po(3), X2～Po(5) $ に従う $X1, X2 $ の和が、$Po(8)$ に従うかやってみよう。

まずは、$X1＋X2$ の分布を求めてみる。

```python
# X1～Po(3), X2～Po(5)
x1s = []
y1s = []
x2s = []
y2s = []
l1 = 3
l2 = 5

for x in range(15):
    x1s.append(x)
    y1s.append(my_poisson(x, l1))

for x in range(15):
    x2s.append(x)
    y2s.append(my_poisson(x, l2))
    
y1s /= np.array(y1s).sum()
y2s /= np.array(y2s).sum()

# 10000回X1, X2のサンプルを取得し、X1+X2の分布(出現回数)を取得する
sample_size = 10000
l1_l2 = [0] * 20
for i in range(sample_size):
    # X1から1つサンプルを取得
    x1_sample = np.random.choice(x1s, p=y1s)
    # X2から1つサンプルを取得
    x2_sample = np.random.choice(x2s, p=y2s)
    x1_x2[x1_sample + x2_sample] += 1

# 分布(出現回数）を標本数で割って確率を求める
x1_x2 = np.array(x1_x2)
x1_x2 = x1_x2/sample_size 
```

次に $Po(8)$ を求めよう。

```python
xs = []
ys = []
for x in range(20):
    xs.append(x)
    ys.append(my_poisson(x, 8))
```

$X1＋X2$ の分布と $Po(8)$ の分布を重ねてみよう

```python
fig = plt.figure(figsize=(8,5))    
ax = fig.add_subplot(1,1,1)
ax.bar(range(20), x1_x2[:20], color="r", alpha=0.3)
ax.bar(xs, ys, color="b", alpha=0.3)
```

紫の色のところが重なった部分になるが、ほぼ重なっていることが分かる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329816/cb5a88c2-2316-0e1f-ab99-7317604e588a.png)


# 中心極限定理を確認しよう
二項分布の時と同様に中心極限定理を確認しよう。
中心極限定理によれば、nが大きい時、ポアソン分布からの標本平均を用いた統計量 $\sqrt{n}(\bar{X_{n}}-λ)$は、正規分布$N(0,λ)$ に分布収束する。

$λ=5, n=100$ の条件でやってみよう。

```python
# X～Po(5)の確率関数によるサンプリングの準備
n = 100
l = 5
x1s = [] 
y1s = []
for x in range(30):
    x1s.append(x)
    y1s.append(my_poisson(x, l))

y1s /= np.array(y1s).sum()    

# n=100で標本平均を求め、統計量を計算することを1000回繰り返す
traial_time = 1000
targets = []

for i in range(traial_time):
    x1_samples = []
    # n=100サンプリングする
    for j in range(n):
        x1_sample = np.random.choice(x1s, p=y1s)
        x1_samples.append(x1_sample)

    # n=100の標本平均を求める
    x1_samples_mean = np.array(x1_samples).mean()
    # print(x1_samples_mean)
    
    # 統計量を計算する
    target = math.sqrt(n) * (x1_samples_mean - l) 
    targets.append(target)

# 描画する
fig = plt.figure(figsize=(8,5))    
ax = fig.add_subplot(1,1,1)
ax.hist(targets, bins=200, color="b")
```

そうすると以下のような分布が得られる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329816/b61ac030-7a60-1205-3346-53c72fc1fd2b.png)

これが正規分布 $N(0,λ)$ に収束するということだから、これもグラフを描いて比較してみよう。
normal というのは正規分布の確率密度関数である。

```python
# 正規分布を表示
fig = plt.figure(figsize=(8,5))
ax = fig.add_subplot(1,1,1)
x = np.linspace(-7, 7, 100)
y = normal(x, 0, l)
ax.plot(x, y, color="r")
```

上を実行すると下のようなグラフが得られる。
$\sqrt{n}(\bar{X_{n}}-λ)$ の分布が、下の正規分布に非常に近いということが分かる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329816/2c3b1302-67c6-44db-1d20-98f51465189d.png)

# 少数の法則を確認しよう
二項分布 $B(N, p)$ において $p=λ/N$ とし、$N$ を大きくするとポアソン分布 $Po(λ)$ に分布収束する。これを少数の法則という。

$N=100$, $λ=3$ で実験してみよう。

まずは、$X～Bin(N, λ/N)$ のからのサンプリング

```python
# X～Bin(N, l/N)の確率関数によるサンプリングの準備
N = 100
l = 3
x1s_bin = [] 
y1s_bin = []

#X～Bin(N, l/N) の確率関数によるサンプリング
for x in range(N+1):
    x1s_bin.append(x)
    y1s_bin.append(binomial(x, N, l/N))
```

次に $X～λ(3)$ のサンプリング

```python
x1s_po = []
y1s_po = []
for x in range(20):
    x1s_po.append(x)
    y1s_po.append(my_poisson(x, 3))

fig = plt.figure(figsize=(8,5))    
ax = fig.add_subplot(1,1,1)
ax.bar(x1s_po[:10], y1s_po[:10])
```

$X～Bin(N, λ/N)$ と $X～λ(3)$ を重ねてみよう。

```python
fig = plt.figure(figsize=(8,5))    
ax = fig.add_subplot(1,1,1)
ax.bar(x1s_bin[:10], y1s_bin[:10], color="red", alpha=0.3)
ax.bar(x1s_po[:10], y1s_po[:10], color="blue", alpha=0.3)
```

以下の紫のところが重なった部分だが、きれいに重なっているのが分かる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329816/7515a2ac-5b4d-117f-0ef7-08c9b9707612.png)