- AB 테스트

A/B 검정은 두 버전(A와 B) 중 어느 것이 더 효과적인지 평가하기 위해 사용되는 검정 방법
마케팅, 웹사이트 디자인 등에서 많이 사용됨
사용자들을 두 그룹으로 나누고, 각 그룹에 다른 버전을 제공한 후 반응을 비교
일반적으로 전환율, 클릭률, 구매수, 방문 기간, 방문한 페이지 수, 특정 페이지 방문 여부, 매출 등의 지표 비교
목적: 두 그룹 간의 변화가 우연이 아니라 통계적으로 유의미한지를 확인
import numpy as np
import scipy.stats as stats
# 가정된 전환율 데이터
group_a = np.random.binomial(1, 0.30, 100) # 30% 전환율을 가지는 표본그룹
group_b = np.random.binomial(1, 0.45, 100) # 45% 전환율을 가지는 표본그룹
print(f'{group_a} \n {group_b}')
# t-test를 이용한 비교
t_stat, p_val = stats.ttest_ind(group_a, group_b)
print(f"T-Statistic: {t_stat}, P-value: {p_val}")
- stats.ttest_ind: 독립표본 t-검정(Independent Samples t-test)을 수행하며 두 개의 독립된 집단 간 평균의 차이가 유의미한지 평가, 두 집단의 데이터 배열을 입력으로 받아서 t-통계량과 p-값을 반환
- t-통계량 (statistic): t-검정 통계량, 두 집단 간 평균 차이의 크기와 방향 나타냄
- p-값 (pvalue): p-값은 귀무 가설이 참일 때, 현재 데이터보다 극단적인 결과가 나올 확률, 이 값이 유의수준(α)보다 작으면 귀무 가설을 기각하고 이 값이 유의수준(α)보다 크면 귀무 가설을 기각하지 않음 → 유의수준(0.05)보다 작으므로 귀무 가설을 기각 하고 이 두 값의 차이가 유의미함을 의미함.
- 가설검정

표본 데이터를 통해 모집단의 가설을 검증하는 과정
귀무가설(H0, NULL)과 대립가설(H1, Alternative)을 설정하고, 귀무가설을 기각할지를 결정
- 확증적 자료분석: 미리 가설들을 먼저 세운 다음 가설을 검증해 나가는 분석
- 탐색적 자료분석(EDA): 가설을 먼저 정하지 않고 데이터를 탐색해보면서 가설 후보들을 찾고 데이터의 특징을 찾는 분석
통계적 유의성: 결과가 우연히 발생한 것이 아니라 어떤 효과가 실제로 존재함을 나타내는 지표
p값은 귀무 가설이 참일 경우 관찰된 통계치가 나올 확률을 의미 (p값이 0.05 미만이면 귀무 가설 기각, 대립 가설 채택, 결과를 통계적으로 유의하다고 판단)
- 신뢰구간: 특정 모수가 포함될 범위를 제공, 모집단의 평균이 특정 범위 내에 있을 것이라는 확률을 나타냄
- 가설검정: 모수가 특정 값과 같은지 다른지 테스트
가설검정 사용 예
- 새로운 약물이 기존 약물보다 효과가 있는지 검정
- 이 때 새로운 약물은 기존 약물과 큰 차이가 없다는 것이 귀무가설
- 대립가설은 새로운 약물이 기존 약물과 대비해 효과가 있다는 것
# 기존 약물(A)와 새로운 약물(B)의 효과 데이터 생성
A = np.random.normal(50, 10, 100) # 평균, 표주편차, 샘플수
B = np.random.normal(55, 10, 100)
# 평균 효과 계산
mean_A = np.mean(A)
mean_B = np.mean(B)
# t-검정 수행
t_stat, p_value = stats.ttest_ind(A, B)
print(f'A 평균 효과: {mean_A} \nB 평균 효과: {mean_B} \n')
print(f't-검정 통계량: {t_stat} \np-값: {p_value} \n')
# t-검정의 p-값 확인 (위 예시에서 계산된 p-값 사용)
print(f'p-값: {p_value}')
if p_value < 0.05:
print('귀무가설을 기각합니다. 통계적으로 유의미한 차이가 있습니다.')
else:
print('귀무가설을 기각하지 않습니다. 통계적으로 유의미한 차이가 없습니다.')
- t_stat: 두 집단의 평균 차이가 표준 오차의 몇 배인지 나타내는 값
- t_stat의 절댓값이 크면 → 두 집단이 진짜로 다를 가능성이 큼
- t_stat의 절댓값이 작으면 → 평균 차이가 우연일 가능성이 큼
- | t_stat | = 0.5 → 평균 차이가 거의 없다
- | t_stat | = 2.5 → 평균 차이가 표준오차의 2.5배 → 꽤 큰 차이다
- | t_stat | = 5.0 → 엄청난 차이
- t_stat 값이 클수록 p_value는 작아짐 → t_stat이 크면 귀무가설(두 집단이 같다)을 기각할 근거가 커짐
- t 검정
두 집단 간의 평균 차이가 통계적으로 유의미한지 확인하는 검정
- 독립표본 t검정: 두 독립된 그룹의 평균을 비교 (두 클래스의 시험 성적 비교)
- 대응표본 t검정: 동일한 그룹의 사전/사후 평균을 비교 (다이어트 전후 체중 비교)
- 다중검정
여러 가설을 동시에 검정
각 검정마다 유의수준을 조정하지 않으면 1종 오류(귀무가설이 참인데 기각하는 오류) 발생 확률이 증가
본페로니 보정, 튜키 보정, 던넷 보정, 윌리엄스 보정 등을 통해 유의수준을 작게 만들어 더 엄격하게 만들면 오류 발생 감소
# 세 그룹의 데이터 생성
np.random.seed(42)
group_A = np.random.normal(10, 2, 30)
group_B = np.random.normal(12, 2, 30)
group_C = np.random.normal(11, 2, 30)
# 세 그룹 간 평균 차이에 대한 t검정 수행
p_values = []
p_values.append(stats.ttest_ind(group_A, group_B).pvalue)
p_values.append(stats.ttest_ind(group_A, group_C).pvalue)
p_values.append(stats.ttest_ind(group_B, group_C).pvalue)
alpha = 0.05
for i, p in enumerate(p_values):
if p < alpha:
print(f'검정 {i + 1}: 유의미한 차이 발견 (p = {p:.4f})')
else:
print(f'검정 {i + 1}: 유의미한 차이 없음 (p = {p:.4f})')
# 본페로니 보정 적용
adjusted_alpha = alpha / len(p_values) # 유의수준이 더 낮아짐
# 결과 출력
print(f'본페로니 보정된 유의수준: {adjusted_alpha:.4f}')
for i, p in enumerate(p_values):
if p < adjusted_alpha:
print(f'검정 {i + 1}: 유의미한 차이 발견 (p = {p:.4f})')
else:
print(f'검정 {i + 1}: 유의미한 차이 없음 (p = {p:.4f})')
- 카이제곱검정
범주형 데이터의 표본 분포가 모집단 분포와 일치하는지 겁정(적합도 검정) 하거나 두 범주형 변수 간의 독립성을 검정(독립성 검정)
- 적합도 검정
- 관찰된 분포와 기대된 분포가 일치하는지 검정 (귀무가설: 관측값은 기대분포와 같다)
- p값이 높으면 데이터가 귀무 가설에 잘 맞음. 즉, 관찰된 데이터와 귀무 가설이 적합
- p값이 낮으면 데이터가 귀무 가설에 잘 맞지 않음. 즉, 관찰된 데이터와 귀무 가설이 부적합
- 독립성 검정
- 두 범주형 변수 간의 독립성 검정 (귀무가설: 두 변수는 서로 독립이다)
- p값이 높으면 두 변수 간의 관계가 연관성이 없음. 즉, 독립성이 있음
- p값이 낮으면 두 변수 간의 관계가 연관성이 있음. 즉, 독립성이 없음. 유의미함
# 적합도 검정
observed = [20, 30, 25, 25]
expected = [25, 25, 25, 25]
chi2_stat, p_value = stats.chisquare(observed, f_exp=expected)
print(f'적합도 검정 카이제곱 통계량: {chi2_stat}, p값: {p_value}')
# 독립성 검정
observed = np.array([[10, 10, 20], [20, 20, 40]])
chi2_stat, p_value, dof, expected = stats.chi2_contingency(observed)
print(f'독립성 검정 카이제곱 통계량: {chi2_stat}, p-값: {p_value}')
# 나이와 흡연 여부 독립성 검정
observed = np.array([[30, 10], [20, 40]])
chi2_stat, p_value, dof, expected = stats.chi2_contingency(observed)
print(f'독립성 검정 카이제곱 통계량: {chi2_stat}, p-값: {p_value}')
- 적합도 검정
- 관측된 데이터가 기대한 분포(25,25,25,25)와 유의미하게 다른가?
- 귀무가설: 관측값은 기대분포와 같다
- p_value < 0.05: 귀무가설 기각 → 기대분포와 다르다 → 유의미한 차이가 있음
- p_value >= 0.05: 귀무가설 유지 → 기대분포와 같다 → 유의미한 차이가 없음
- scipy.stats.chisquare 함수 사용. 관찰된 빈도 분포가 기대된 빈도 분포와 일치하는지 평가
- 독립성 검정
- 귀무가설: 두 변수는 서로 독립이다. (즉, 아무 관련성 없다)
- p_value < 0.05: 귀무가설 기각 → 독립이 아니다 → 두 변수는 관련 있음
- p_value >= 0/05: 귀무가설 유지 → 독립이다 → 관계 없음
- scipy.stats.chi2_contingency 함수 사용.
- dof: 자유도.= (행의 수 -1) * (열의수 -1)
- expected: 기대 빈도. 행 합계와 열 합계를 사용하여 계산된 이론적 빈도
- 나이와 흡연 여부 독립성 검정
- p_value < 0.05: 나이와 흡연은 관련 있음
- p_value >= 0/05: 나이와 흡연은 관련 없음
- 제 1종 오류와 제 2종 오류

- 제 1종 오류 "위양성"
- 귀무가설이 참인데 기각하는 오류
- 잘못된 긍정을 의미 (새로운 약물이 효과가 없는데 효과가 있다고 하는 것)
- α를 경계로 귀무가설을 기각하기 때문에 제1종 오류가 α만큼 발생 → 유의수준을 정함으로써 1종 오류 제어 가능
- 만약, 유의수준이 0.05라면 100번 중 5번 정도 일어날 수 있는 제 1종 오류는 감수하겠다는 것
- 다중 검정시 제 1종 오류가 증가하는 이유
- 하나의 검정에서 제 1종 오류가 발생하지 않을 확률은 1- α
- m개의 독립된 검정에서 제 1종 오류가 전혀 발생하지 않을 확률은 (1- α)^m
- m개의 검정에서 하나 이상의 제 1종 오류가 발생할 확률은 1-(1- α)^m
- m이 커질수록 제 1종 오류가 발생할 확률은 빠르게 증가함
- 제 2종 오류 "위음성"
- 귀무가설이 거짓인데 기각하지 않는 오류
- 잘못된 부정을 의미 (효과가 있는데 효과가 없다고 하는 것)
- 제 2종 오류가 일어날 확률은 β로 정의, 일어나지 않을 확률은 검정력(1- β)으로 정의
- but, 이를 직접 통제할 수는 없음 → 표본 크기 n이 커질 수록 β가 작아짐
- α와 β는 상충관계에 있어서 너무 낮은 α를 가지면 β는 더욱 높아짐
'통계학 공부' 카테고리의 다른 글
| ANOVA, 카이제곱 검정과 상관분석 (0) | 2026.02.18 |
|---|---|
| 가설검정 실습 (단일, 독립, 대응표본 t검정) (1) | 2026.02.18 |
| 가설검정 (단일, 독립, 대응표본 t검정) (1) | 2026.02.17 |
| 선형회귀, 다항회귀, 스플라인회귀, 피어슨 / 비모수 / 상호정보 상관계수 (1) | 2026.01.10 |
| 스튜던트t분포, 카이제곱분포, 이항분포, 푸아송분포 (0) | 2026.01.10 |