확률의 뜻

단원 02 경우의 수와 확률 · 「확률과 통계」 · 1차시(45분)

개념

각 결과가 일어날 가능성이 모두 같은 시행에서, 사건 \(A\)수학적 확률은 전체 경우의 수에 대한 사건 \(A\)의 경우의 수의 비율입니다.

\[P(A) = \frac{n(A)}{n(S)}\]

“시행을 늘릴수록 상대도수가 확률에 가까워진다”는 대수의 법칙은 04단원 표본평균의 분포에서 다시 만납니다.

한편 실제로 시행을 \(n\)번 반복했을 때 사건 \(A\)가 일어난 상대도수 \(\dfrac{r_n}{n}\)\(n\)이 커질수록 일정한 값에 가까워지는데, 이 값을 통계적 확률이라고 합니다. 동전 앞면처럼 수학적 확률을 아는 시행에서는 상대도수가 바로 그 수학적 확률로 다가갑니다. 아래 앱에서 시행 횟수를 늘려가며 파란 곡선(상대도수)이 점선(수학적 확률)에 달라붙는 모습을 확인해 보세요.

만지며 배우기

#| '!! shinylive warning !!': |
#|   shinylive does not work in self-contained HTML documents.
#|   Please set `embed-resources: false` in your metadata.
#| standalone: true
#| viewerHeight: 640

# matplotlib·numpy 없이 stdlib + 인라인 SVG 로만 그린다
import random
from shiny import App, reactive, render, ui

ACCENT = "#2563eb"
INK = "#111827"
MUTED = "#6b7280"
GRID = "#e5e7eb"

TRIALS = {
    "coin": {"name": "동전 던지기 — 앞면", "p": 0.5, "label": "1/2"},
    "die": {"name": "주사위 던지기 — 6의 눈", "p": 1 / 6, "label": "1/6"},
}

def running_mean(hits):
    out = []
    s = 0
    for i, h in enumerate(hits):
        s += h
        out.append(s / (i + 1))
    return out

def line_svg(run, p):
    n = len(run)
    W, H, ml, mr, mt, mb = 470, 300, 40, 12, 14, 32
    pw, ph = W - ml - mr, H - mt - mb
    def X(i):
        return ml + (i / max(1, n - 1)) * pw
    def Y(v):
        return mt + ph - v * ph
    grid = ""
    for v in (0.0, 0.25, 0.5, 0.75, 1.0):
        yy = Y(v)
        grid += (f'<line x1="{ml}" y1="{yy:.1f}" x2="{W-mr}" y2="{yy:.1f}" stroke="{GRID}"/>'
                 f'<text x="{ml-6}" y="{yy+3:.1f}" font-size="9" fill="{MUTED}" '
                 f'text-anchor="end">{v:.2f}</text>')
    step = max(1, n // 400)
    idx = list(range(0, n, step))
    if idx[-1] != n - 1:
        idx.append(n - 1)
    path = "M" + " L".join(f"{X(i):.1f},{Y(run[i]):.1f}" for i in idx)
    pline = (f'<line x1="{ml}" y1="{Y(p):.1f}" x2="{W-mr}" y2="{Y(p):.1f}" '
             f'stroke="{INK}" stroke-width="1" stroke-dasharray="5 3"/>')
    return (
        f'<svg viewBox="0 0 {W} {H}" style="width:100%;height:auto;'
        'font-family:-apple-system,sans-serif;">'
        f'{grid}{pline}<path d="{path}" fill="none" stroke="{ACCENT}" stroke-width="1.4"/>'
        f'<text x="{ml+pw/2:.0f}" y="{H-4}" font-size="10" fill="{MUTED}" '
        'text-anchor="middle">시행 횟수</text>'
        f'<text x="6" y="{mt-2}" font-size="10" fill="{MUTED}">상대도수</text>'
        '</svg>'
    )

app_ui = ui.page_sidebar(
    ui.sidebar(
        ui.input_select(
            "trial", "시행 종류",
            {k: v["name"] for k, v in TRIALS.items()},
        ),
        ui.input_slider("n", "시행 횟수 n", min=10, max=10000, value=200, step=10),
        ui.input_action_button("redraw", "다시 시행"),
        width=240,
    ),
    ui.card(
        ui.card_header("상대도수의 변화(파랑) vs 수학적 확률(점선)"),
        ui.output_ui("freq_plot"),
    ),
    ui.card(ui.output_ui("readout")),
    fillable=True,
)

def server(input, output, session):
    @reactive.calc
    def draws():
        input.redraw()  # 버튼을 누르면 새로 시행
        p = TRIALS[input.trial()]["p"]
        return [1 if random.random() < p else 0 for _ in range(input.n())]

    @render.ui
    def freq_plot():
        p = TRIALS[input.trial()]["p"]
        return ui.HTML(line_svg(running_mean(draws()), p))

    @render.ui
    def readout():
        sc = TRIALS[input.trial()]
        hits = draws()
        n = len(hits)
        rel = sum(hits) / n
        return ui.HTML(
            f'<p class="hs-readline">'
            f"{n:,}번 시행했을 때 상대도수는 {rel:.4f}, "
            f"수학적 확률은 {sc['label']} = {sc['p']:.4f}이고 "
            f"차이는 {abs(rel - sc['p']):.4f}입니다. "
            f"시행을 늘릴수록 상대도수가 수학적 확률에 가까워지는데, "
            f"이렇게 정해지는 값이 통계적 확률입니다.</p>"
        )

app = App(app_ui, server)

앱의 핵심 계산은 이 몇 줄이 전부입니다.

import random

p = 1 / 6                                # 주사위 6의 눈의 수학적 확률
n = 10000

hits = [1 if random.random() < p else 0 for _ in range(n)]

run, s = [], 0                           # 시점별 상대도수
for i, h in enumerate(hits):
    s += h
    run.append(s / (i + 1))

print(run[9], run[99], run[-1], p)       # n이 커질수록 p에 접근

스스로 확인

\(n = 10\)일 때는 누를 때마다 끝값이 0.1 단위로 크게 출렁이지만, \(n = 10000\)일 때는 거의 매번 수학적 확률 바로 근처에서 끝납니다. 상대도수는 시행 횟수가 충분히 커야 믿을 수 있는 값이 됩니다.

각 결과의 가능성이 같다고 볼 수 없으므로 경우의 수의 비로는 구할 수 없습니다. 대신 실제로 많이 던져 보고 상대도수가 다가가는 값, 즉 통계적 확률로 정합니다. 의약품의 치료 효과, 야구 타율처럼 현실의 많은 확률이 이 방식으로 정해집니다.