표본추출
개념
조사 대상 전체(모집단)를 빠짐없이 조사하는 것이 전수조사, 그 일부(표본)만 뽑아 조사하는 것이 표본조사입니다. 전교생 400명의 평균 키를 알고 싶을 때, 표본 \(n\)명을 잘 뽑으면 표본평균 \(\bar{x}\)로 모평균 \(m\)을 추정할 수 있습니다.
\[\text{모집단(크기 } N=400\text{)} \;\longrightarrow\; \text{표본(크기 } n\text{)} \;\longrightarrow\; \bar{x} \approx m\]
급식 만족도 조사를 한 반에서만 하면 안 되는 이유 — 그 반의 특성(급식실과의 거리, 학년 분위기 등)이 결과를 치우치게 하기 때문입니다. 표본은 모집단 전체를 골고루 대표해야 합니다.
표본을 뽑는 대표적인 방법은 세 가지입니다. 단순임의추출은 제비뽑기처럼 모두에게 같은 확률을 주고, 계통추출은 명부에서 일정한 간격으로 뽑으며, 층화추출은 남/녀처럼 집단을 층으로 나눈 뒤 각 층에서 비례하여 뽑습니다. 아래 앱에서 방법을 바꿔 가며 어떤 점들이 뽑히는지, 표본평균이 모평균에서 얼마나 벗어나는지 관찰해 보세요.
만지며 배우기
#| '!! 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"
# 모집단: 전교생 400명의 키 (고정된 시드 → 항상 같은 학교)
random.seed(42)
def _clip(v, lo, hi):
return max(lo, min(hi, v))
male = [_clip(random.gauss(173, 6), 145, 195) for _ in range(200)] # 앞 200명: 남
female = [_clip(random.gauss(161, 5), 145, 195) for _ in range(200)] # 뒤 200명: 여
POP = male + female
POP_MEAN = sum(POP) / len(POP)
METHOD_NOTE = {
"srs": "단순임의추출은 모두에게 같은 확률을 주는 제비뽑기입니다. 어디에도 치우치지 않지만, 우연히 한쪽 층이 많이 뽑힐 수도 있습니다.",
"sys": "계통추출은 명부에서 일정 간격으로 뽑아 빠르고 간편합니다. 다만 명부에 규칙적인 배열이 있으면 치우칠 수 있습니다.",
"strat": "층화추출은 남녀 비율(200:200)을 표본에서도 그대로 유지하므로, 남녀 키 차이 때문에 생기는 치우침이 적습니다.",
}
def grid_svg(idx):
idxs = set(idx)
cell, ox, oy = 16, 26, 8
body = ""
for i in range(400):
c, r = i % 20, i // 20
x, y = ox + c * cell, oy + r * cell
if i in idxs:
body += f'<circle cx="{x}" cy="{y}" r="4.5" fill="{ACCENT}"/>'
else:
body += f'<circle cx="{x}" cy="{y}" r="2.4" fill="#d1d5db"/>'
ydiv = oy + 10 * cell - cell / 2
body += (f'<line x1="{ox-6}" y1="{ydiv}" x2="{ox+19*cell+6}" y2="{ydiv}" '
f'stroke="#9ca3af" stroke-width="0.8" stroke-dasharray="2 3"/>'
f'<text x="12" y="{oy+4.5*cell:.0f}" font-size="12" fill="{MUTED}" '
f'text-anchor="middle">남</text>'
f'<text x="12" y="{oy+14.5*cell:.0f}" font-size="12" fill="{MUTED}" '
f'text-anchor="middle">여</text>')
W, H = ox + 20 * cell + 6, oy + 20 * cell
return (f'<svg viewBox="0 0 {W} {H}" style="width:100%;max-height:340px;'
f'height:auto;font-family:-apple-system,sans-serif;">{body}</svg>')
app_ui = ui.page_sidebar(
ui.sidebar(
ui.input_select(
"method", "추출 방법",
{"srs": "단순임의추출", "sys": "계통추출", "strat": "층화추출(남/녀)"},
),
ui.input_slider("n", "표본 크기 n", min=10, max=100, value=40, step=10),
ui.input_action_button("redraw", "다시 추출"),
width=240,
),
ui.card(
ui.card_header("전교생 400명(회색) 중 이번에 뽑힌 표본(파랑)"),
ui.output_ui("grid_plot"),
),
ui.card(ui.output_ui("readout")),
fillable=True,
)
def server(input, output, session):
@reactive.calc
def sample_idx():
input.redraw() # 버튼을 누르면 새로 추출
n = input.n()
method = input.method()
if method == "srs":
return random.sample(range(400), n)
if method == "sys":
k = 400 // n
start = random.randrange(k)
return list(range(start, 400, k))[:n]
# 층화추출: 남녀에서 절반씩
half = n // 2
idx_m = random.sample(range(200), half)
idx_f = [200 + i for i in random.sample(range(200), n - half)]
return idx_m + idx_f
@render.ui
def grid_plot():
return ui.HTML(grid_svg(sample_idx()))
@render.ui
def readout():
idx = sample_idx()
xbar = sum(POP[i] for i in idx) / len(idx)
return ui.HTML(
f'<p class="hs-readline">'
f"모평균 m = {POP_MEAN:.2f} cm · 이번 표본평균 x̄ = {xbar:.2f} cm · "
f"차이 = {abs(POP_MEAN - xbar):.2f} cm. "
f"{METHOD_NOTE[input.method()]}</p>"
)
app = App(app_ui, server)
세 가지 추출 방법의 핵심은 인덱스를 고르는 방식의 차이입니다.
import random
srs = random.sample(range(400), 40) # 단순임의추출
k = 400 // 40 # 계통추출: 간격 10
sys_ = list(range(random.randrange(k), 400, k))
boys = random.sample(range(200), 20) # 층화추출: 남 20 + 여 20
girls = [200 + i for i in random.sample(range(200), 20)]
strat = boys + girls스스로 확인
어떤 400명 중 누가 뽑히느냐가 매번 달라지기 때문입니다. 표본평균 \(\bar{x}\)는 표본에 따라 값이 변하는 확률변수입니다 — 이 사실이 다음 모듈 “표본평균의 분포”의 출발점입니다.
단순임의추출은 우연히 남학생(또는 여학생)만 많이 뽑힐 수 있고, 남녀 키 차이가 약 12 cm이므로 표본평균이 크게 치우칩니다. 층화추출은 남녀를 10명씩 강제로 나누어 뽑아 이런 치우침을 원천 차단합니다. 앱에서 두 방법의 “차이” 값을 여러 번 비교해 보세요.