3강: 무작위성과 세기
Python으로 “골턴 보드” 패턴을 만들면서 배워요:
- np.random.default_rng로 만드는 난수
- 1과 0으로 세는 True와 False
- np.bincount로 세기
- 리스트 컴프리헨션
- 공식과 대조해 보는 시뮬레이션
먼저 보기
클릭하면 YouTube에서 재생돼요.
"""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에서 실행할 수 있어요. 노트북은 영어로 되어 있어요.
한 줄씩
rng = np.random.default_rng()numpy의 난수 생성기예요. default_rng(1)처럼 수를 하나 주면 실행할 때마다 같은 ‘무작위’ 수가 나와요.
bins = (rng.random((balls, rows)) < p).sum(axis=1)0과 1 사이의 난수 5,000 × 12개로 이루어진 표예요. p보다 작은 수는 True, 곧 오른쪽으로 튄 거예요. 한 행을 더하면 그 행의 True 개수가 세어지고, 그것이 공이 들어간 칸이에요.
counts = np.bincount(bins, minlength=rows + 1)0번부터 12번까지 각 칸에 공이 몇 개 들어갔는지 세요. minlength는 비어 있는 가장자리 칸도 0으로 세어지게 해 줘요.
expected = [balls * comb(rows, i) * p**i * (1 - p) ** (rows - i) for i in k]리스트 컴프리헨션이에요. 칸 i마다 이항분포 공식에 공의 개수를 곱해요.
plt.bar(k, counts, color="#5eead4", label="balls")칸마다 막대 하나. 그다음에 그리는 흰 선은 비교해 볼 공식이에요.
직접 해 보기
스크립트를 두 번 실행해 보세요. 막대가 똑같나요? 그다음 매번 똑같이 나오게 해 보세요.
힌트
default_rng에 수를 하나 주세요.
정답
막대는 실행할 때마다 조금씩 달라요. rng = np.random.default_rng(1)로 하면 매번 같은 결과가 나와요.
12줄 보드에서 공 5,000개 중 몇 개가 가운데 칸에 들어가야 할까요?
힌트
가운데 칸의 비율은 comb(12, 6) / 2**12예요.
정답
5000 × 924 ÷ 4096 ≈ 1128.
p = 0.65로 보드를 기울여 보세요. 이제 종의 중심은 어디일까요?
힌트
중심은 rows · p예요.
정답
12 × 0.65 = 7.8이라서 꼭대기가 7번과 8번 칸으로 옮겨 가요.
퀴즈
플래시카드
앞면을 읽고, 뒷면의 내용을 스스로 말해 본 다음 카드를 펼쳐 보세요.
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예요.