T- test 예제
Python의 scipy.stats 모듈을 활용해 T 검정을 수행하는 예시입니다. 실제로 분석할 때는 정규성, 등분산성 등 사전 가정(assumptions)을 확인한 후에 진행해야 합니다. 여기서는 이해를 돕기 위해 랜덤으로 데이터를 생성해 시연하겠습니다.
1. 환경 설정
import numpy as np
import pandas as pd
from scipy.stats import ttest_1samp, ttest_ind, ttest_rel, shapiro
numpy: 랜덤 데이터 생성 및 배열 연산pandas: 데이터 프레임 형태로 결과 정리scipy.stats: t 검정(1표본, 2표본, 대응) 및 정규성 검정(Shapiro-Wilk) 함수
2. 단일 표본 t 검정 (One-sample t-test)
2.1 가상의 데이터 생성
- 모집단 평균이 50이라고 알려진(혹은 가정되는) 상황이 있고, 표본 20개를 뽑았다고 가정해 봅시다.
- 실제 표본은 정규 분포(, )에서 랜덤 생성하되, 완전히 일치하지 않을 수 있습니다. μ=50\mu = 50 σ=5\sigma = 5
np.random.seed(123) # 재현 가능성을 위해 난수 고정
sample_data = np.random.normal(loc=50, scale=5, size=20)
print(sample_data)
2.2 정규성 검정 (Shapiro-Wilk Test)
- T 검정을 하기 전, 표본이 정규 분포를 따른다고 가정할 수 있는지 검토합니다.
stat, p_value = shapiro(sample_data)
print("Shapiro-Wilk Test:")
print(f"Test Statistic = {stat:.4f}, p-value = {p_value:.4f}")
- 일반적으로
p-value > 0.05라면 정규분포를 따른다고 볼 수 있습니다(엄격한 규칙은 아니며, 여러 지표 함께 고려).
2.3 단일 표본 t 검정
- 귀무가설(): 표본이 뽑힌 모집단의 평균은 50과 같다. H0H_0
- 대립가설(): 모집단의 평균은 50과 다르다. H1H_1
# 모집단 평균(mu0)를 50으로 가정
mu0 = 50
t_stat, p_val = ttest_1samp(sample_data, popmean=mu0)
print("\nOne-Sample t-test:")
print(f"T-statistic = {t_stat:.4f}, p-value = {p_val:.4f}")
alpha = 0.05
if p_val < alpha:
print("=> 귀무가설 기각: 모수평균이 50이 아닐 가능성이 유의함.")
else:
print("=> 귀무가설 채택: 모수평균이 50과 유의하게 다르다고 보기 어려움.")
3. 독립 표본 t 검정 (Independent two-sample t-test)
3.1 가상의 두 집단 데이터 생성
- 예:
group_A와group_B라는 두 집단에서 각각 30개 표본을 뽑았다고 가정 group_A: 평균 55, 표준편차 10group_B: 평균 50, 표준편차 10- 실제 집단의 차이를 보기 위해 일부러 평균을 달리 설정
np.random.seed(456) # 난수 고정
group_A = np.random.normal(loc=55, scale=10, size=30)
group_B = np.random.normal(loc=50, scale=10, size=30)
# 데이터 프레임으로 묶어 보기 좋게 관리
df_ind = pd.DataFrame({
'group': ['A']*30 + ['B']*30,
'value': np.concatenate([group_A, group_B])
})
print(df_ind.head())
3.2 정규성 검정 & 등분산 검정
- 각 그룹이 정규분포를 따르는지: Shapiro-Wilk
- 두 그룹 간 등분산 가정이 가능한지: Levene’s test or Bartlett’s test 등(아래는 Levene 예시)
from scipy.stats import levene
stat_A, p_A = shapiro(group_A)
stat_B, p_B = shapiro(group_B)
print("\nShapiro-Wilk Test for group A:")
print(f"p-value = {p_A:.4f}")
print("Shapiro-Wilk Test for group B:")
print(f"p-value = {p_B:.4f}")
stat_lev, p_lev = levene(group_A, group_B)
print("\nLevene’s test for equal variances:")
print(f"Test Statistic = {stat_lev:.4f}, p-value = {p_lev:.4f}")
p_lev > 0.05라면 등분산 가정을 어느 정도 수용할 수 있다고 해석(엄격한 기준 아님).
3.3 독립 표본 t 검정
- 귀무가설(): 두 집단의 평균은 같다(). H0H_0 μA=μB\mu_A = \mu_B
- 대립가설(): 두 집단의 평균은 다르다(). H1H_1 μA≠μB\mu_A \neq \mu_B
# 등분산 가정이 성립한다고 가정할 경우
t_stat_ind, p_val_ind = ttest_ind(group_A, group_B, equal_var=True)
print("\nIndependent Two-Sample t-test (등분산 가정):")
print(f"T-statistic = {t_stat_ind:.4f}, p-value = {p_val_ind:.4f}")
alpha = 0.05
if p_val_ind < alpha:
print("=> 귀무가설 기각: 두 집단 평균에 유의한 차이가 있음.")
else:
print("=> 귀무가설 채택: 두 집단 평균에 유의한 차이가 있다고 보기 어려움.")
- 등분산 가정이 어렵다면
equal_var=False옵션을 주어 Welch’s t-test를 수행합니다:
t_stat_welch, p_val_welch = ttest_ind(group_A, group_B, equal_var=False)
4. 대응 표본 t 검정 (Paired t-test)
4.1 가상의 전후 측정 데이터 생성
- 예: 같은 10명의 혈압을 약 복용 전(before), **약 복용 후(after)**에 측정했다고 가정
- 실제로는 동일인을 반복 측정하기 때문에 두 표본이 종속적(paired)입니다.
np.random.seed(789)
before = np.random.normal(loc=140, scale=10, size=10)
# 약 복용 후 평균이 5 정도 낮아졌다고 가정
after = before - np.random.normal(loc=5, scale=3, size=10)
df_paired = pd.DataFrame({
'before': before,
'after': after
})
print(df_paired)
4.2 정규성 검정 (차이값)
- 대응 표본 t 검정에서는 “차이(after - before)”가 정규분포를 따르는지 확인
diff = df_paired['after'] - df_paired['before']
stat_diff, p_diff = shapiro(diff)
print("\nShapiro-Wilk Test for difference (after - before):")
print(f"Test Statistic = {stat_diff:.4f}, p-value = {p_diff:.4f}")
4.3 대응 표본 t 검정
- 귀무가설(): 복용 전후(또는 대응 표본 간) 평균 차이가 0 H0H_0
- 대립가설(): 평균 차이가 0이 아님 H1H_1
t_stat_rel, p_val_rel = ttest_rel(df_paired['before'], df_paired['after'])
print("\nPaired t-test:")
print(f"T-statistic = {t_stat_rel:.4f}, p-value = {p_val_rel:.4f}")
alpha = 0.05
if p_val_rel < alpha:
print("=> 귀무가설 기각: 복용 전후 평균에 유의한 차이가 있음.")
else:
print("=> 귀무가설 채택: 복용 전후 평균이 유의하게 다르다고 보기 어려움.")
5. 전체 예시 코드
아래는 위 단계를 하나로 묶어 놓은 예시 코드입니다.
import numpy as np
import pandas as pd
from scipy.stats import ttest_1samp, ttest_ind, ttest_rel, shapiro, levene
# -------------------
# 1. One-sample t-test
# -------------------
np.random.seed(123)
sample_data = np.random.normal(loc=50, scale=5, size=20)
# 정규성 검정
stat, p_value = shapiro(sample_data)
print("[One-sample] Shapiro-Wilk Test")
print(f" p-value = {p_value:.4f}")
# 단일 표본 t 검정 (모집단 가정 평균=50)
t_stat, p_val = ttest_1samp(sample_data, popmean=50)
print("[One-sample] t-test:")
print(f" T-statistic = {t_stat:.4f}, p-value = {p_val:.4f}")
# -------------------
# 2. Independent two-sample t-test
# -------------------
np.random.seed(456)
group_A = np.random.normal(loc=55, scale=10, size=30)
group_B = np.random.normal(loc=50, scale=10, size=30)
# 그룹별 정규성 검정
stat_A, p_A = shapiro(group_A)
stat_B, p_B = shapiro(group_B)
print("\n[Two-sample] Shapiro-Wilk Test A & B")
print(f" p-value(A) = {p_A:.4f}, p-value(B) = {p_B:.4f}")
# 등분산 검정
stat_lev, p_lev = levene(group_A, group_B)
print("[Two-sample] Levene’s test for equal variances:")
print(f" Stat = {stat_lev:.4f}, p-value = {p_lev:.4f}")
# 독립 표본 t 검정
t_stat_ind, p_val_ind = ttest_ind(group_A, group_B, equal_var=True)
print("[Two-sample] Independent t-test (equal_var=True):")
print(f" T-statistic = {t_stat_ind:.4f}, p-value = {p_val_ind:.4f}")
# -------------------
# 3. Paired t-test
# -------------------
np.random.seed(789)
before = np.random.normal(loc=140, scale=10, size=10)
after = before - np.random.normal(loc=5, scale=3, size=10)
# 차이의 정규성 검정
diff = after - before
stat_diff, p_diff = shapiro(diff)
print("\n[Paired] Shapiro-Wilk Test for difference:")
print(f" p-value = {p_diff:.4f}")
# 대응 표본 t 검정
t_stat_rel, p_val_rel = ttest_rel(before, after)
print("[Paired] t-test:")
print(f" T-statistic = {t_stat_rel:.4f}, p-value = {p_val_rel:.4f}")
6. 결과 해석
- p-value < 0.05: 일반적으로 유의수준(α=0.05\alpha=0.05)에서 ‘통계적으로 유의하다’고 해석합니다.
- One-sample: 모집단 평균이 가정한 값(예: 50)과 다를 가능성이 유의
- Two-sample: 두 그룹 평균이 유의하게 다름
- Paired: 짝지어진 두 시점(실험 전·후)의 평균 차이가 유의
- p-value ≥ 0.05: 차이가 통계적으로 유의하지 않음(“귀무가설을 기각할 근거가 부족하다”).
7. 요약
- 단일 표본 t 검정(One-sample t-test)
- 모집단의 평균이 특정 값과 다른지 비교할 때 사용
ttest_1samp(표본, popmean=가정평균)
- 독립 표본 t 검정(Independent two-sample t-test)
- 서로 독립적인 두 집단의 평균 비교
- 등분산 가정 시
ttest_ind(A, B, equal_var=True), 등분산 가정을 못 하면equal_var=False(Welch’s t-test)
- 대응 표본 t 검정(Paired t-test)
- 동일한 집단의 전후 측정이나, 쌍으로 묶인 자료를 분석할 때 사용
ttest_rel(before, after)
- 정규성·등분산성·독립성 가정 확인이 중요하며, 가정이 크게 위배되는 경우에는 다른 비모수 검정(e.g., Wilcoxon test, Mann-Whitney U test 등)을 고려해야 합니다. 이렇게 실제 예시 데이터와 Python 코드를 통해 T 검정을 수행할 수 있습니다. 실제 연구나 분석 상황에서는 가정들이 충족되는지 꼼꼼히 확인하고, 결과(p-value, 효과 크기, 신뢰구간 등)를 종합적으로 해석하는 것이 중요합니다.
T 검정 실습 가이드
실습 1: 단일 표본 T 검정
문제 상황
한 고등학교 3학년 학급(25명)의 수학 성적이 전국 평균(70점)과 차이가 있는지 검정하고자 합니다.
데이터
scores = [75, 68, 82, 69, 71, 73, 65, 77, 78, 74,
72, 68, 76, 65, 71, 69, 73, 70, 75, 72,
74, 76, 71, 68, 73]
분석 코드
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
import seaborn as sns
# 기술통계량 확인
print("평균:", np.mean(scores))
print("표준편차:", np.std(scores, ddof=1))
# 정규성 검정
_, p_value = stats.shapiro(scores)
print("Shapiro-Wilk 검정 p-value:", p_value)
# 히스토그램 그리기
plt.figure(figsize=(8, 6))
sns.histplot(scores, kde=True)
plt.title("점수 분포")
plt.show()
# 단일표본 t검정 수행
t_stat, p_value = stats.ttest_1samp(scores, popmean=70)
print("t-통계량:", t_stat)
print("p-value:", p_value)
해석 연습
- 정규성 가정이 만족되는가?
- t-통계량과 p-value는 무엇을 의미하는가?
- 귀무가설을 기각해야 하는가?
실습 2: 독립 표본 T 검정
문제 상황
새로운 학습 방법의 효과를 검증하기 위해 실험군(20명)과 대조군(20명)의 시험 점수를 비교합니다.
데이터
control = [68, 72, 65, 70, 73, 69, 71, 74, 70, 72,
67, 71, 73, 69, 70, 75, 71, 68, 72, 70]
experiment = [75, 78, 72, 76, 74, 77, 73, 80, 75, 77,
76, 73, 75, 74, 78, 75, 74, 76, 78, 75]
분석 코드
# 기술통계량
print("대조군 평균:", np.mean(control))
print("실험군 평균:", np.mean(experiment))
# 등분산 검정
_, levene_p = stats.levene(control, experiment)
print("Levene's test p-value:", levene_p)
# 독립표본 t검정
t_stat, p_value = stats.ttest_ind(control, experiment)
print("t-통계량:", t_stat)
print("p-value:", p_value)
# 시각화
plt.figure(figsize=(10, 6))
plt.boxplot([control, experiment], labels=['대조군', '실험군'])
plt.title("그룹별 점수 분포")
plt.show()
해석 연습
- 등분산 가정이 만족되는가?
- 새로운 학습 방법이 효과가 있다고 할 수 있는가?
- 효과 크기(Cohen’s d)를 계산하고 해석하시오.
실습 3: 대응 표본 T 검정
문제 상황
15명의 학생들을 대상으로 학습 프로그램 전후의 성적 변화를 분석합니다.
데이터
before = [65, 70, 68, 72, 69, 71, 67, 73, 70, 68,
72, 69, 71, 70, 68]
after = [70, 75, 71, 76, 73, 74, 70, 78, 73, 71,
75, 72, 74, 73, 70]
분석 코드
# 차이값 계산
differences = np.array(after) - np.array(before)
# 기술통계량
print("평균 차이:", np.mean(differences))
print("차이의 표준편차:", np.std(differences, ddof=1))
# 대응표본 t검정
t_stat, p_value = stats.ttest_rel(after, before)
print("t-통계량:", t_stat)
print("p-value:", p_value)
# 시각화
plt.figure(figsize=(10, 6))
plt.scatter(before, after)
plt.plot([60, 80], [60, 80], 'r--') # 45도 선
plt.xlabel("프로그램 전 점수")
plt.ylabel("프로그램 후 점수")
plt.title("전후 점수 비교")
plt.show()
해석 연습
- 프로그램의 효과가 통계적으로 유의한가?
- 산점도에서 45도 선의 의미는 무엇인가?
- 95% 신뢰구간을 계산하고 해석하시오.
종합 실습: 가설검정 절차
다음 과제를 수행하시오:
- 실제 데이터를 수집하여 적절한 T 검정 방법 선택하기
- 데이터 탐색 및 가정 검토하기
- T 검정 수행 및 결과 해석하기
- 결과를 보고서 형식으로 작성하기
보고서 작성 가이드
- 연구 목적
- 데이터 수집 방법
- 기술통계량
- 가정 검토 결과
- T 검정 결과
- 결과 해석 및 결론
- 한계점 및 제언
추가 연습문제
- 다음 중 T 검정이 적절한 상황을 고르시오:
- A. n=50, 모표준편차 알려짐
- B. n=15, 모표준편차 모름
- C. n=100, 정규성 위배
- 독립표본 t검정에서 등분산 가정이 위배되었다면?
- A. 그대로 진행한다
- B. Welch’s t검정을 사용한다
- C. 비모수 검정을 사용한다
- p-value가 0.06일 때의 해석은?
- A. 귀무가설 기각
- B. 귀무가설 채택
- C. 추가 데이터 필요
참고자료
- Python 통계분석 라이브러리
- scipy.stats
- statsmodels
- pingouin
- 추천 시각화 도구
- matplotlib
- seaborn
- plotly
- 보고서 작성 도구
- Jupyter Notebook
- R Markdown
- LaTeX
- 프로젝트 예시 아래는 Python을 활용해 T 검정을 실습하는 예시입니다. 단일 표본, 독립 표본, 대응 표본 각각에 대해 가상의 데이터를 생성하여 검정 과정을 단계별로 시연합니다. 실제 프로젝트에서는 자신의 데이터를 불러와서 동일한 과정을 적용하면 됩니다.
T 검정 실습
본 실습에서는 다음과 같은 라이브러리를 사용합니다:
- numpy: 난수 생성, 수치 연산
- pandas: 데이터프레임 생성, 관리
- scipy.stats: 통계 검정(T 검정, 정규성 검정 등)
- (선택) matplotlib.pyplot: 시각화(Q-Q 플롯, 히스토그램 등)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import ttest_1samp, ttest_ind, ttest_rel, shapiro, levene
# 노트북 환경에서 그래프가 바로 표시되도록
%matplotlib inline
1. 단일 표본 T 검정 (One-Sample t-test)
1.1 데이터 생성
- 예: 모평균이 50이라 알려진(또는 가정되는) 상황에서, 실제로 표본 20개를 추출
- 여기서는 정규분포(평균=50, 표준편차=5)를 사용하여 임의 데이터 생성
# 재현성을 위해 시드 고정
np.random.seed(100)
# 단일 표본 (size=20)
sample = np.random.normal(loc=50, scale=5, size=20)
print("생성된 표본:\n", sample)
1.2 정규성 검정
- 표본 크기가 작다면(30 미만) 정규성 가정이 특히 중요
- Shapiro-Wilk 검정을 수행해 p-value를 확인
stat, p_value = shapiro(sample)
print("\n[Shapiro-Wilk Test] 단일 표본 정규성 검정")
print(f"검정 통계량(stat) = {stat:.4f}, p-value = {p_value:.4f}")
if p_value > 0.05:
print("=> 정규성을 만족한다고 볼 수 있음")
else:
print("=> 정규성을 만족하지 않는 것으로 보일 수 있음")
- Q-Q 플롯 혹은 히스토그램으로 분포 모양을 추가 확인할 수도 있습니다:
plt.hist(sample, bins=8, edgecolor='black')
plt.title("Histogram of Sample (One-Sample T-test)")
plt.xlabel("Value")
plt.ylabel("Frequency")
plt.show()
1.3 T 검정 수행
- 귀무가설(): 모평균(μ)이 50이다. H0H_0
- 대립가설(): 모평균(μ)이 50이 아니다(양측 검정). H1H_1
t_stat, p_val = ttest_1samp(sample, popmean=50)
print("\n[One-Sample t-test]")
print(f"T-statistic = {t_stat:.4f}, p-value = {p_val:.4f}")
alpha = 0.05
if p_val < alpha:
print("=> 귀무가설 기각: 평균이 50과 유의하게 다름")
else:
print("=> 귀무가설 채택(기각 실패): 평균이 50과 다르다고 보기 어려움")
2. 독립 표본 T 검정 (Independent Two-Sample t-test)
2.1 데이터 생성
- 가상 시나리오:
- 그룹 A: 평균 55, 표준편차 8
- 그룹 B: 평균 50, 표준편차 8
- 각각 30명씩 표본을 추출했다고 가정
np.random.seed(200)
group_A = np.random.normal(loc=55, scale=8, size=30)
group_B = np.random.normal(loc=50, scale=8, size=30)
df_two = pd.DataFrame({
'group': ['A']*30 + ['B']*30,
'value': np.concatenate([group_A, group_B])
})
print(df_two.head(6))
2.2 정규성, 등분산성 검정
- 각 그룹이 정규성을 만족하는지(Shapiro-Wilk)
- 두 그룹의 분산이 동일한지(Levene’s test)
# 그룹별 나누기
group_A_vals = df_two[df_two['group']=='A']['value']
group_B_vals = df_two[df_two['group']=='B']['value']
# (1) 정규성
stat_A, p_A = shapiro(group_A_vals)
stat_B, p_B = shapiro(group_B_vals)
print("\n[Shapiro-Wilk Test] 정규성 검정")
print(f"Group A -> p-value: {p_A:.4f}")
print(f"Group B -> p-value: {p_B:.4f}")
# (2) 등분산성 (Levene test)
stat_lev, p_lev = levene(group_A_vals, group_B_vals)
print("\n[Levene’s Test] 등분산성 검정")
print(f"검정 통계량(stat) = {stat_lev:.4f}, p-value = {p_lev:.4f}")
2.3 독립 표본 T 검정
- 귀무가설(): (두 집단 평균이 같다) H0H_0 μA=μB\mu_A = \mu_B
- 대립가설(): H1H_1 μA≠μB\mu_A \neq \mu_B
# 등분산 가정 여부에 따라 옵션 변경
# Levene’s test 결과를 바탕으로 선택 (p_lev > 0.05면 등분산 가정해도 무방)
t_stat_ind, p_val_ind = ttest_ind(group_A_vals, group_B_vals, equal_var=True)
print("\n[Independent Two-Sample t-test]")
print(f"T-statistic = {t_stat_ind:.4f}, p-value = {p_val_ind:.4f}")
alpha = 0.05
if p_val_ind < alpha:
print("=> 귀무가설 기각: 두 그룹의 평균이 유의하게 다름")
else:
print("=> 귀무가설 채택(기각 실패): 두 그룹 평균 차이가 유의하다고 보기 어려움")
참고: 만약 등분산 가정이 위배되었다면(p_lev < 0.05),
3. 대응 표본 T 검정 (Paired t-test)
3.1 데이터 생성
- 가상 시나리오: 동일한 15명을 대상으로, “약 복용 전(before)”과 “약 복용 후(after)”의 혈압(수축기) 측정
- 실제로는 한 사람당 2회 측정했기에, 두 표본은 “대응”(paired) 관계
np.random.seed(300)
before = np.random.normal(loc=140, scale=10, size=15)
# 약 복용 후 혈압이 약간 낮아졌다고 가정(평균적으로 5 정도 차이)
after = before - np.random.normal(loc=5, scale=3, size=15)
df_paired = pd.DataFrame({
'before': before,
'after': after
})
df_paired.head()
3.2 차이값의 정규성 검정
- 대응 표본 t 검정에서 중요한 것은 “차이값(after - before)”가 정규분포인지
- diff=after−before\text{diff} = \text{after} - \text{before}
diff = df_paired['after'] - df_paired['before']
stat_diff, p_diff = shapiro(diff)
print("\n[Shapiro-Wilk Test] 대응 표본 차이값 정규성 검정")
print(f"검정 통계량(stat) = {stat_diff:.4f}, p-value = {p_diff:.4f}")
if p_diff > 0.05:
print("=> 차이값이 정규성을 만족한다고 볼 수 있음")
else:
print("=> 차이값이 정규성을 만족하지 않는 것으로 보일 수 있음")
3.3 대응 표본 T 검정
- 귀무가설(): 복용 전과 후의 평균 혈압은 차이가 없다(평균 차이가 0). H0H_0
- 대립가설(): 복용 전후 평균 혈압 차이가 0이 아니다. H1H_1
t_stat_rel, p_val_rel = ttest_rel(df_paired['before'], df_paired['after'])
print("\n[Paired t-test]")
print(f"T-statistic = {t_stat_rel:.4f}, p-value = {p_val_rel:.4f}")
alpha = 0.05
if p_val_rel < alpha:
print("=> 귀무가설 기각: 복용 전후 평균에 유의한 차이가 있음")
else:
print("=> 귀무가설 채택(기각 실패): 통계적으로 유의한 차이를 찾지 못함")
4. 결과 해석
- 유의확률 p-value를 확인해, 미리 설정한 유의수준(, 예: 0.05)보다 작은지 비교합니다. α\alpha
- p-value < 0.05 → 귀무가설 기각 → “차이가 있다”
- p-value ≥ 0.05 → 귀무가설 채택(혹은 기각하지 않음) → “차이가 통계적으로 유의하지 않음”
- 주의: “귀무가설 채택”은 “두 집단(시점)의 평균이 완전히 같다”가 아니라, “차이가 있다고 단언할 근거가 부족하다”라는 의미입니다.
5. 추가 분석: 효과 크기와 시각화 (선택)
5.1 효과 크기 (예: Cohen’s d)
- Cohen’s d: 두 그룹 평균 차이를 표준편차(풀링, 혹은 두 집단의 평균 표준편차)로 나눈 값
- 일반적으로 d=0.2(작은 효과), 0.5(중간 효과), 0.8(큰 효과) 정도로 해석
- Python에서 별도 계산 함수가 없으므로 직접 구현할 수 있습니다.
def cohen_d(group1, group2):
# 독립 표본의 경우
# 1) 각 그룹 크기, 평균, 분산
n1, n2 = len(group1), len(group2)
mean1, mean2 = np.mean(group1), np.mean(group2)
var1, var2 = np.var(group1, ddof=1), np.var(group2, ddof=1)
# 2) pooled std
pooled_std = np.sqrt(((n1-1)*var1 + (n2-1)*var2) / (n1+n2-2))
return (mean1 - mean2) / pooled_std
# 예: 독립 표본 group_A, group_B
d_value = cohen_d(group_A_vals, group_B_vals)
print("\n[Cohen's d for Independent Samples]")
print(f"d = {d_value:.3f}")
만약 대응 표본이라면, 대응 표본용 효과 크기 산출 방식(차이값 기반)이 필요합니다.
5.2 시각화 예시
- 박스플롯(Boxplot) 혹은 바플롯(Bar plot) 등을 통해 그룹 간 분포나 평균 차이를 시각적으로 확인
import seaborn as sns
sns.boxplot(x='group', y='value', data=df_two)
plt.title("Boxplot: Group A vs. Group B")
plt.show()
6. 요약
- T 검정 종류
- 단일 표본: 표본 평균 vs. 특정 기준값 비교
- 독립 표본: 두 집단(독립) 간 평균 비교
- 대응 표본: 동일 개체(쌍)의 전후 변화 비교
- 가정
- (1) 정규성
- (2) 독립성(해당되는 경우)
- (3) 등분산성(독립 표본 시)
- 분석 절차
- 가설 설정 → 검정 통계량(T) 계산 → p-value vs. α 비교 → 결론(귀무가설 기각/채택)
- 해석
- p < α → “차이가 있다” (유의함)
- p ≥ α → “차이를 발견하지 못함” (유의하지 않음)
- 효과 크기(Cohen’s d 등)로 실제 차이가 어느 정도인지 보완적으로 판단 위 코드를 하나씩 실행해보면서, 각 검정의 p-value가 어떻게 나오는지 확인해보세요. 또한, 정규성 검정이나 박스플롯을 통해 데이터 분포를 함께 살펴보면 더욱 깊이 있는 해석이 가능합니다. 이를 통해 실제 프로젝트나 연구에서, T 검정을 올바르게 적용하고, “단순 유의성”뿐만 아니라 “얼마나 차이가 나는가(효과 크기)”까지 종합적으로 판단하는 역량을 기를 수 있습니다. 아래는 Python을 활용해 T 검정을 실습하는 예시입니다. 단일 표본, 독립 표본, 대응 표본 각각에 대해 가상의 데이터를 생성하여 검정 과정을 단계별로 시연합니다. 실제 프로젝트에서는 자신의 데이터를 불러와서 동일한 과정을 적용하면 됩니다.
T 검정 실습
본 실습에서는 다음과 같은 라이브러리를 사용합니다:
- numpy: 난수 생성, 수치 연산
- pandas: 데이터프레임 생성, 관리
- scipy.stats: 통계 검정(T 검정, 정규성 검정 등)
- (선택) matplotlib.pyplot: 시각화(Q-Q 플롯, 히스토그램 등)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import ttest_1samp, ttest_ind, ttest_rel, shapiro, levene
# 노트북 환경에서 그래프가 바로 표시되도록
%matplotlib inline
1. 단일 표본 T 검정 (One-Sample t-test)
1.1 데이터 생성
- 예: 모평균이 50이라 알려진(또는 가정되는) 상황에서, 실제로 표본 20개를 추출
- 여기서는 정규분포(평균=50, 표준편차=5)를 사용하여 임의 데이터 생성
# 재현성을 위해 시드 고정
np.random.seed(100)
# 단일 표본 (size=20)
sample = np.random.normal(loc=50, scale=5, size=20)
print("생성된 표본:\n", sample)
1.2 정규성 검정
- 표본 크기가 작다면(30 미만) 정규성 가정이 특히 중요
- Shapiro-Wilk 검정을 수행해 p-value를 확인
stat, p_value = shapiro(sample)
print("\n[Shapiro-Wilk Test] 단일 표본 정규성 검정")
print(f"검정 통계량(stat) = {stat:.4f}, p-value = {p_value:.4f}")
if p_value > 0.05:
print("=> 정규성을 만족한다고 볼 수 있음")
else:
print("=> 정규성을 만족하지 않는 것으로 보일 수 있음")
- Q-Q 플롯 혹은 히스토그램으로 분포 모양을 추가 확인할 수도 있습니다:
plt.hist(sample, bins=8, edgecolor='black')
plt.title("Histogram of Sample (One-Sample T-test)")
plt.xlabel("Value")
plt.ylabel("Frequency")
plt.show()
1.3 T 검정 수행
- 귀무가설(): 모평균(μ)이 50이다. H0H_0
- 대립가설(): 모평균(μ)이 50이 아니다(양측 검정). H1H_1
t_stat, p_val = ttest_1samp(sample, popmean=50)
print("\n[One-Sample t-test]")
print(f"T-statistic = {t_stat:.4f}, p-value = {p_val:.4f}")
alpha = 0.05
if p_val < alpha:
print("=> 귀무가설 기각: 평균이 50과 유의하게 다름")
else:
print("=> 귀무가설 채택(기각 실패): 평균이 50과 다르다고 보기 어려움")
2. 독립 표본 T 검정 (Independent Two-Sample t-test)
2.1 데이터 생성
- 가상 시나리오:
- 그룹 A: 평균 55, 표준편차 8
- 그룹 B: 평균 50, 표준편차 8
- 각각 30명씩 표본을 추출했다고 가정
np.random.seed(200)
group_A = np.random.normal(loc=55, scale=8, size=30)
group_B = np.random.normal(loc=50, scale=8, size=30)
df_two = pd.DataFrame({
'group': ['A']*30 + ['B']*30,
'value': np.concatenate([group_A, group_B])
})
print(df_two.head(6))
2.2 정규성, 등분산성 검정
- 각 그룹이 정규성을 만족하는지(Shapiro-Wilk)
- 두 그룹의 분산이 동일한지(Levene’s test)
# 그룹별 나누기
group_A_vals = df_two[df_two['group']=='A']['value']
group_B_vals = df_two[df_two['group']=='B']['value']
# (1) 정규성
stat_A, p_A = shapiro(group_A_vals)
stat_B, p_B = shapiro(group_B_vals)
print("\n[Shapiro-Wilk Test] 정규성 검정")
print(f"Group A -> p-value: {p_A:.4f}")
print(f"Group B -> p-value: {p_B:.4f}")
# (2) 등분산성 (Levene test)
stat_lev, p_lev = levene(group_A_vals, group_B_vals)
print("\n[Levene’s Test] 등분산성 검정")
print(f"검정 통계량(stat) = {stat_lev:.4f}, p-value = {p_lev:.4f}")
2.3 독립 표본 T 검정
- 귀무가설(): (두 집단 평균이 같다) H0H_0 μA=μB\mu_A = \mu_B
- 대립가설(): H1H_1 μA≠μB\mu_A \neq \mu_B
# 등분산 가정 여부에 따라 옵션 변경
# Levene’s test 결과를 바탕으로 선택 (p_lev > 0.05면 등분산 가정해도 무방)
t_stat_ind, p_val_ind = ttest_ind(group_A_vals, group_B_vals, equal_var=True)
print("\n[Independent Two-Sample t-test]")
print(f"T-statistic = {t_stat_ind:.4f}, p-value = {p_val_ind:.4f}")
alpha = 0.05
if p_val_ind < alpha:
print("=> 귀무가설 기각: 두 그룹의 평균이 유의하게 다름")
else:
print("=> 귀무가설 채택(기각 실패): 두 그룹 평균 차이가 유의하다고 보기 어려움")
참고: 만약 등분산 가정이 위배되었다면(p_lev < 0.05),
3. 대응 표본 T 검정 (Paired t-test)
3.1 데이터 생성
- 가상 시나리오: 동일한 15명을 대상으로, “약 복용 전(before)”과 “약 복용 후(after)”의 혈압(수축기) 측정
- 실제로는 한 사람당 2회 측정했기에, 두 표본은 “대응”(paired) 관계
np.random.seed(300)
before = np.random.normal(loc=140, scale=10, size=15)
# 약 복용 후 혈압이 약간 낮아졌다고 가정(평균적으로 5 정도 차이)
after = before - np.random.normal(loc=5, scale=3, size=15)
df_paired = pd.DataFrame({
'before': before,
'after': after
})
df_paired.head()
3.2 차이값의 정규성 검정
- 대응 표본 t 검정에서 중요한 것은 “차이값(after - before)”가 정규분포인지
- diff=after−before\text{diff} = \text{after} - \text{before}
diff = df_paired['after'] - df_paired['before']
stat_diff, p_diff = shapiro(diff)
print("\n[Shapiro-Wilk Test] 대응 표본 차이값 정규성 검정")
print(f"검정 통계량(stat) = {stat_diff:.4f}, p-value = {p_diff:.4f}")
if p_diff > 0.05:
print("=> 차이값이 정규성을 만족한다고 볼 수 있음")
else:
print("=> 차이값이 정규성을 만족하지 않는 것으로 보일 수 있음")
3.3 대응 표본 T 검정
- 귀무가설(): 복용 전과 후의 평균 혈압은 차이가 없다(평균 차이가 0). H0H_0
- 대립가설(): 복용 전후 평균 혈압 차이가 0이 아니다. H1H_1
t_stat_rel, p_val_rel = ttest_rel(df_paired['before'], df_paired['after'])
print("\n[Paired t-test]")
print(f"T-statistic = {t_stat_rel:.4f}, p-value = {p_val_rel:.4f}")
alpha = 0.05
if p_val_rel < alpha:
print("=> 귀무가설 기각: 복용 전후 평균에 유의한 차이가 있음")
else:
print("=> 귀무가설 채택(기각 실패): 통계적으로 유의한 차이를 찾지 못함")
4. 결과 해석
- 유의확률 p-value를 확인해, 미리 설정한 유의수준(, 예: 0.05)보다 작은지 비교합니다. α\alpha
- p-value < 0.05 → 귀무가설 기각 → “차이가 있다”
- p-value ≥ 0.05 → 귀무가설 채택(혹은 기각하지 않음) → “차이가 통계적으로 유의하지 않음”
- 주의: “귀무가설 채택”은 “두 집단(시점)의 평균이 완전히 같다”가 아니라, “차이가 있다고 단언할 근거가 부족하다”라는 의미입니다.
5. 추가 분석: 효과 크기와 시각화 (선택)
5.1 효과 크기 (예: Cohen’s d)
- Cohen’s d: 두 그룹 평균 차이를 표준편차(풀링, 혹은 두 집단의 평균 표준편차)로 나눈 값
- 일반적으로 d=0.2(작은 효과), 0.5(중간 효과), 0.8(큰 효과) 정도로 해석
- Python에서 별도 계산 함수가 없으므로 직접 구현할 수 있습니다.
def cohen_d(group1, group2):
# 독립 표본의 경우
# 1) 각 그룹 크기, 평균, 분산
n1, n2 = len(group1), len(group2)
mean1, mean2 = np.mean(group1), np.mean(group2)
var1, var2 = np.var(group1, ddof=1), np.var(group2, ddof=1)
# 2) pooled std
pooled_std = np.sqrt(((n1-1)*var1 + (n2-1)*var2) / (n1+n2-2))
return (mean1 - mean2) / pooled_std
# 예: 독립 표본 group_A, group_B
d_value = cohen_d(group_A_vals, group_B_vals)
print("\n[Cohen's d for Independent Samples]")
print(f"d = {d_value:.3f}")
만약 대응 표본이라면, 대응 표본용 효과 크기 산출 방식(차이값 기반)이 필요합니다.
5.2 시각화 예시
- 박스플롯(Boxplot) 혹은 바플롯(Bar plot) 등을 통해 그룹 간 분포나 평균 차이를 시각적으로 확인
import seaborn as sns
sns.boxplot(x='group', y='value', data=df_two)
plt.title("Boxplot: Group A vs. Group B")
plt.show()
6. 요약
- T 검정 종류
- 단일 표본: 표본 평균 vs. 특정 기준값 비교
- 독립 표본: 두 집단(독립) 간 평균 비교
- 대응 표본: 동일 개체(쌍)의 전후 변화 비교
- 가정
- (1) 정규성
- (2) 독립성(해당되는 경우)
- (3) 등분산성(독립 표본 시)
- 분석 절차
- 가설 설정 → 검정 통계량(T) 계산 → p-value vs. α 비교 → 결론(귀무가설 기각/채택)
- 해석
- p < α → “차이가 있다” (유의함)
- p ≥ α → “차이를 발견하지 못함” (유의하지 않음)
- 효과 크기(Cohen’s d 등)로 실제 차이가 어느 정도인지 보완적으로 판단 위 코드를 하나씩 실행해보면서, 각 검정의 p-value가 어떻게 나오는지 확인해보세요. 또한, 정규성 검정이나 박스플롯을 통해 데이터 분포를 함께 살펴보면 더욱 깊이 있는 해석이 가능합니다. 이를 통해 실제 프로젝트나 연구에서, T 검정을 올바르게 적용하고, “단순 유의성”뿐만 아니라 “얼마나 차이가 나는가(효과 크기)”까지 종합적으로 판단하는 역량을 기를 수 있습니다.