初級 · ガルトンボード

レッスン3:乱数と数えあげ

Pythonで 「ガルトンボード」 を作りながら、次のことを学びます:

  • np.random.default_rng による乱数
  • 1と0として数えられる True と False
  • np.bincount で数える
  • リスト内包表記
  • 公式と照らし合わせるシミュレーション

まず見てみる

クリックするとYouTubeから再生されます。

galton-board.py
"""Galton board: every ball goes left or right at random at each of 12 rows of pegs.
Run: python galton-board.py   (needs: pip install numpy matplotlib)
"""
from math import comb

import numpy as np
import matplotlib.pyplot as plt

plt.style.use("dark_background")

rows, balls, p = 12, 5000, 0.5  # p: the chance of bouncing right
rng = np.random.default_rng()

bins = (rng.random((balls, rows)) < p).sum(axis=1)  # a ball's bin = how often it went right
counts = np.bincount(bins, minlength=rows + 1)

k = np.arange(rows + 1)
expected = [balls * comb(rows, i) * p**i * (1 - p) ** (rows - i) for i in k]  # the binomial curve

plt.figure(figsize=(7, 4))
plt.bar(k, counts, color="#5eead4", label="balls")
plt.xlabel("bin = times the ball went right")
plt.plot(k, expected, color="white", label="C(n, k) p^k (1-p)^(n-k)")
plt.legend()
plt.show()

# Try: p = 0.65 tilts the board; rows = 24 makes the bell narrower for its width

このコンピューターにPythonが入っていませんか?ノートブックなら、同じスクリプト、練習問題、答えを、ブラウザ上のGoogle Colabで実行できます。ノートブックは英語です。

1行ずつ

  1. rng = np.random.default_rng()

    numpy の乱数生成器です。default_rng(1) のように数を渡すと、実行するたびに同じ「でたらめな」数が出ます。

  2. bins = (rng.random((balls, rows)) < p).sum(axis=1)

    0から1までの乱数を 5,000 × 12 個並べた表です。p より小さいものは True、つまり右への跳ね返りです。1行を足し合わせるとその行の True の数が数えられ、それが玉の入る箱になります。

  3. counts = np.bincount(bins, minlength=rows + 1)

    0から12までの各箱に、玉がいくつ入ったか。minlength のおかげで、空っぽの端の箱も0として数えられます。

  4. expected = [balls * comb(rows, i) * p**i * (1 - p) ** (rows - i) for i in k]

    リスト内包表記です。箱 i ごとの二項分布の公式に、玉の数を掛けます。

  5. plt.bar(k, counts, color="#5eead4", label="balls")

    箱ひとつにつき棒を1本。そのあとに描く白い線が公式で、見比べるためのものです。

やってみよう

  1. スクリプトを2回実行してみましょう。棒は同じですか?次に、毎回同じ結果になるようにしてみましょう。

    ヒント

    default_rng に数を渡します。

    答え

    棒は毎回少しずつ違います。rng = np.random.default_rng(1) にすると、毎回同じ結果になります。

  2. 12段で、玉5,000個のうちいくつが真ん中の箱に入るはずですか?

    ヒント

    真ん中の箱の割合は comb(12, 6) / 2**12 です。

    答え

    5000 × 924 ÷ 4096 ≈ 1128。

  3. p = 0.65 でボードを傾けてみましょう。釣鐘の中心は今どこにありますか?

    ヒント

    中心は rows · p です。

    答え

    12 × 0.65 = 7.8 なので、山は箱7と箱8へ移ります。

クイズ

1. rng.random((5000, 12)) < 0.5 には何が入っていますか?
2. .sum(axis=1) で玉の箱がわかるのはなぜですか?
3. np.bincount([0, 2, 2, 3]) はどうなりますか?
4. default_rng(1) で何が変わりますか?
5. 二項分布の公式で、箱kへの道の数を数えているのはどの部分ですか?

フラッシュカード

表を読み、裏に何があるかを自分で言ってみてから、カードを開いてください。

  • np.random.default_rng(seed)

    乱数生成器。同じシードなら同じ数が出ます。

  • array < 0.5

    True と False の配列。足し算では True が1として数えられます。

  • np.bincount(xs)

    0、1、2、… の各整数が xs に何回現れるか。

  • [f(i) for i in k]

    リスト内包表記。k のすべての要素に f を適用した新しいリスト。

  • comb(n, k)

    n個からk個を選ぶ方法の数。math.comb(12, 6) は924です。

このフラッシュカードを別のページで →