입문 · 골턴 보드

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. 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, 곧 오른쪽으로 튄 거예요. 한 행을 더하면 그 행의 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. 스크립트를 두 번 실행해 보세요. 막대가 똑같나요? 그다음 매번 똑같이 나오게 해 보세요.

    힌트

    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예요.

이 플래시카드만 따로 보기 →