빅데이터 분석기사 실기 3유형 (1) — 가설검정 (T-검정·ANOVA)

3유형 통계검정의 절반. 귀무·대립가설부터 단일/독립/대응 T-검정, 분산분석까지 scipy로 한 번에.

3유형은 통계 가설검정. 코드는 한 줄이지만, 가설 설정과 결과 해석에서 점수가 갈린다. 공식을 외우는 게 아니라 언제 어떤 검정을 쓰는지 를 분별하는 시험이다.


3유형은 어떤 시험인가?

항목 내용
배점 30점 (2문제 × 15점)
형식 통계량·p-value·결론 등 여러 값을 단계적으로 답
시간 권장 약 40~50분
주요 도구 scipy.stats, statsmodels
출제 영역 T-검정, 분산분석, 카이제곱, 회귀분석, 로지스틱 회귀

이번 글은 T-검정 + 분산분석까지. 회귀와 카이제곱은 (2)에서 다룬다.


가설검정 기초 — 무조건 외우는 4가지

1. 귀무가설(H₀) vs 대립가설(H₁)

  • 귀무가설(H₀): "차이가 없다 / 효과가 없다 / 같다" — 기본 입장
  • 대립가설(H₁): "차이가 있다 / 효과가 있다 / 다르다" — 입증하고 싶은 것

검정은 H₀를 기각할 충분한 증거가 있는지 본다. H₁을 직접 증명하지 않는다.

2. p-value의 해석

p-value < 0.05  →  귀무가설 기각 → 대립가설 채택 → "유의한 차이가 있다"
p-value ≥ 0.05  →  귀무가설 채택 → "차이가 있다고 보기 어렵다"

문제에서 보통 유의수준 α = 0.05 로 준다.

3. 단측 vs 양측

  • 양측 검정: "A와 B가 다르다" — 방향 무관
  • 단측 검정: "A가 B보다 크다(또는 작다)" — 방향 지정

4. 정규성·등분산성 — 검정 선택의 갈림길

  • 정규성: 데이터가 정규분포를 따르는가? → shapiro 검정
  • 등분산성: 두 집단의 분산이 같은가? → levene 검정
from scipy import stats

stats.shapiro(data)              # p > 0.05 → 정규성 만족
stats.levene(group1, group2)     # p > 0.05 → 등분산 만족

"정규성 검정 먼저 수행한 후~"가 문제에 나오면, 이걸 빼먹지 말 것.


T-검정 — 평균 비교의 3종 세트

(1) 단일표본 T-검정 (one-sample)

한 집단의 평균이 특정 값과 같은가?

예: "이 제품의 평균 무게가 100g과 다른지 검정하라."

H0: μ = 100
H1: μ ≠ 100
from scipy import stats

t_stat, p_value = stats.ttest_1samp(df["weight"], popmean=100)
print(f"t = {t_stat:.4f}, p = {p_value:.4f}")

if p_value < 0.05:
    print("귀무가설 기각: 평균이 100과 다르다")
else:
    print("귀무가설 채택: 평균이 100과 같다고 볼 수 있다")

(2) 독립표본 T-검정 (two-sample, 비대응)

서로 다른 두 집단의 평균을 비교

예: "남자와 여자의 키 평균이 다른가?"

male   = df[df["gender"]=="M"]["height"]
female = df[df["gender"]=="F"]["height"]

# 등분산성 검정 먼저
_, p_levene = stats.levene(male, female)
equal_var = p_levene > 0.05

t_stat, p_value = stats.ttest_ind(male, female, equal_var=equal_var)
print(f"t = {t_stat:.4f}, p = {p_value:.4f}")

equal_var=False이면 Welch's t-test. 등분산성을 만족하지 않을 때 자동으로 보정된다.

(3) 대응표본 T-검정 (paired)

같은 대상의 변화량을 비교 — "전 vs 후"

예: "다이어트 프로그램 전후의 체중 차이가 유의한가?"

t_stat, p_value = stats.ttest_rel(df["before"], df["after"])
print(f"t = {t_stat:.4f}, p = {p_value:.4f}")

같은 사람의 전후 데이터인지 가 핵심 판별 포인트. 같은 사람이면 paired, 다른 그룹이면 ind.

단측 검정으로 바꾸기

기본은 양측. 단측을 원하면 alternative 옵션을 준다.

# H1: μ > 100 (큰 쪽)
stats.ttest_1samp(data, 100, alternative="greater")

# H1: μ < 100 (작은 쪽)
stats.ttest_1samp(data, 100, alternative="less")

# 양측 (기본)
stats.ttest_1samp(data, 100, alternative="two-sided")

분산분석 (ANOVA) — 셋 이상 집단의 평균 비교

T-검정은 두 집단까지. 세 집단 이상의 평균이 같은지 보려면 ANOVA를 쓴다.

H0: μ1 = μ2 = μ3 = ...
H1: 적어도 한 평균은 다르다

일원분산분석 (One-way ANOVA)

from scipy import stats

a = df[df["group"]=="A"]["score"]
b = df[df["group"]=="B"]["score"]
c = df[df["group"]=="C"]["score"]

f_stat, p_value = stats.f_oneway(a, b, c)
print(f"F = {f_stat:.4f}, p = {p_value:.4f}")

p < 0.05 → "적어도 한 집단의 평균이 다르다." 단, 어느 집단이 다른지는 알 수 없다. 사후검정이 필요.

statsmodels로 더 자세히 (ANOVA 표 출력)

import statsmodels.api as sm
from statsmodels.formula.api import ols

model = ols("score ~ C(group)", data=df).fit()
table = sm.stats.anova_lm(model, typ=2)
print(table)

출력에서 PR(>F) 가 p-value, F 가 F 통계량, sum_sq 가 제곱합이다.

사후검정 (Tukey HSD)

ANOVA가 유의했을 때 어느 그룹 vs 어느 그룹이 다른지 확인.

from statsmodels.stats.multicomp import pairwise_tukeyhsd

result = pairwise_tukeyhsd(df["score"], df["group"], alpha=0.05)
print(result)

reject 컬럼이 True인 쌍이 "유의하게 다른 두 그룹"이다.


정규성·등분산성을 만족하지 않을 때 — 비모수 대안

모수 검정 비모수 대안 함수
독립 T검정 Mann-Whitney U stats.mannwhitneyu
대응 T검정 Wilcoxon 부호순위 stats.wilcoxon
일원 ANOVA Kruskal-Wallis stats.kruskal

시험에서 "정규성을 만족하지 않는다고 가정"하면 비모수 검정을 쓰라는 신호다.

stats.mannwhitneyu(g1, g2)
stats.wilcoxon(before, after)
stats.kruskal(a, b, c)

자주 쓰는 표 — 어떤 검정을 쓸까?

상황 검정
한 집단 평균 vs 특정 값 단일표본 T-검정
두 독립 집단 평균 비교 독립표본 T-검정
같은 대상의 전·후 비교 대응표본 T-검정
셋 이상 집단 평균 비교 One-way ANOVA
ANOVA 후 어느 쌍이 다른지 Tukey HSD
정규성 X, 두 독립 집단 Mann-Whitney U
정규성 X, 대응 표본 Wilcoxon
정규성 X, 셋 이상 Kruskal-Wallis

실전 답안 작성 흐름 (점수 받는 패턴)

3유형은 보통 다음과 같은 방식으로 단계별 답을 요구한다.

1. 가설 설정 (H0, H1 명시)
2. 검정 수행 → 통계량, p-value 계산
3. 결론 (귀무가설 기각/채택)

답안 예시 코드 + 출력

# 문제: 그룹 A와 B의 점수 평균이 다른지 유의수준 0.05로 검정하라.
from scipy import stats

a = df[df["group"]=="A"]["score"]
b = df[df["group"]=="B"]["score"]

# (1) 등분산 검정
_, p_lev = stats.levene(a, b)
equal_var = p_lev > 0.05

# (2) T-검정
t_stat, p_value = stats.ttest_ind(a, b, equal_var=equal_var)

print(f"검정통계량 t = {round(t_stat, 4)}")
print(f"p-value      = {round(p_value, 4)}")

# (3) 결론
if p_value < 0.05:
    print("결론: 귀무가설 기각. 두 그룹의 평균은 유의하게 다르다.")
else:
    print("결론: 귀무가설 채택. 두 그룹의 평균이 다르다고 볼 수 없다.")

시험 답안에는 소수점 자리수 지정을 자주 요구한다. round(x, 4) 같은 형식을 마지막에 꼭 챙긴다.


정리

검정 scipy 함수
단일표본 T stats.ttest_1samp(data, popmean)
독립표본 T stats.ttest_ind(g1, g2, equal_var=True/False)
대응표본 T stats.ttest_rel(before, after)
정규성 검정 stats.shapiro(data)
등분산 검정 stats.levene(g1, g2)
일원 ANOVA stats.f_oneway(a, b, c, ...)
Tukey 사후 pairwise_tukeyhsd(values, groups)
비모수 mannwhitneyu, wilcoxon, kruskal

검정을 언제 쓰는지의 분기 트리만 머릿속에 그려두면, 코드는 한 줄이라 무섭지 않다. 다음 글에서는 회귀분석·로지스틱 회귀·카이제곱 으로 3유형을 마무리한다.