학습 내용

  • result.statistic, result.pvalue를 읽는 기본 습관 익히기
  • stats.shapiro(), stats.ttest_1samp(), stats.ttest_ind(), stats.ttest_rel(), stats.f_oneway()의 차이 이해하기
  • alternative='two-sided', 'greater', 'less'가 무엇을 뜻하는지 배우기
  • pvalue를 바탕으로 결과를 짧은 결론 문장으로 바꾸는 방법 익히기

scipy.stats는 통계검정을 할 때 가장 자주 쓰는 도구 중 하나입니다. 이 페이지에서는 검정 공식을 외우기보다, 어떤 상황에서 어떤 함수를 쓰고 결과를 어떻게 읽는지에 집중합니다.

처음에는 아래 흐름만 익혀도 충분합니다. 검정 함수를 실행하고, result.statisticresult.pvalue를 보고, 보통 0.05 기준으로 결론을 내리면 됩니다.

개념

검정 결과 읽기: result.statistic, result.pvalue

통계검정을 실행하면 보통 결과 객체가 돌아오고, 그 안에서 가장 먼저 보는 값이 statisticpvalue입니다.

from scipy import stats

sample = [52, 54, 51, 53, 55]
result = stats.ttest_1samp(sample, popmean=50)

print(round(result.statistic, 3))
print(round(result.pvalue, 3))
print(result.pvalue < 0.05)

실행 결과:

4.243
0.013
True

여기서 statistic은 검정통계량이고, pvalue는 귀무가설이 맞다고 가정했을 때 지금 같은 차이가 우연히 나올 가능성을 보여 주는 값입니다. 초보자 단계에서는 아래처럼 먼저 읽으면 됩니다.

  • pvalue < 0.05: 차이가 있다고 보는 쪽
  • pvalue >= 0.05: 뚜렷한 차이가 없다고 보는 쪽

이 예시는 평균이 50이라고 보기 어렵다는 쪽으로 읽을 수 있습니다.

문제 1statistic 출력하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 1. statistic 출력하기
# result.statistic을 round(..., 2)로 출력해 보세요.
# 가이드: 이미 만들어진 result에서 statistic만 꺼내면 됩니다.

from scipy import stats

sample = [52, 54, 51, 53, 55]
result = stats.ttest_1samp(sample, popmean=50)

문제 2pvalue 출력하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 2. pvalue 출력하기
# result.pvalue를 round(..., 3)으로 출력해 보세요.
# 가이드: pvalue만 골라 round(..., 3) 해 보세요.

from scipy import stats

sample = [52, 54, 51, 53, 55]
result = stats.ttest_1samp(sample, popmean=50)

문제 30.05 기준으로 판단하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 3. 0.05 기준으로 판단하기
# result.pvalue가 0.05보다 작은지 출력해 보세요.
# 가이드: pvalue와 0.05를 직접 비교해 보세요.

from scipy import stats

sample = [52, 54, 51, 53, 55]
result = stats.ttest_1samp(sample, popmean=50)

개념

stats.shapiro(): 정규성 검정

정규성 검정은 “이 데이터가 정규분포를 크게 벗어나지 않는가”를 확인할 때 자주 사용합니다. 가장 많이 쓰는 함수 중 하나가 stats.shapiro()입니다.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

sample = df.loc[df["측정회원성별"] == "M", "신장 : cm"].sample(120, random_state=42)
result = stats.shapiro(sample)

print(len(sample))
print(round(result.statistic, 3))
print(round(result.pvalue, 3))
print(result.pvalue > 0.05)

실행 결과:

120
0.994
0.856
True

이 예시에서는 pvalue가 0.856으로 아주 큽니다. 즉, 정규분포에서 크게 벗어났다고 볼 만한 강한 근거가 없다는 뜻입니다. 정규성 검정은 “정규분포다”를 증명하는 검정이 아니라, “정규분포가 아니다”라고 강하게 말할 근거가 있는지를 보는 검정이라는 점이 중요합니다.

처음 배울 때는 아래처럼 기억하면 충분합니다.

  • pvalue > 0.05: 정규성에서 큰 문제를 발견하지 못함
  • pvalue <= 0.05: 정규성 가정을 다시 점검할 필요가 있음
문제 4샘플 개수 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 4. 샘플 개수 확인하기
# /data/body.csv에서 남성 신장 : cm를 120개 sample(random_state=42)로 뽑았을 때 길이를 출력해 보세요.

import pandas as pd

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드: 남성 행만 고른 뒤 신장 : cm 열을 sample(120, random_state=42) 해 보세요.

문제 5정규성검정 statistic 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 5. 정규성검정 statistic 확인하기
# sample에 stats.shapiro()를 적용한 뒤 statistic을 round(..., 3)으로 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드
# 1. sample을 만드세요.
# 2. stats.shapiro(sample) 결과의 statistic을 출력하세요.

문제 6정규성검정 pvalue 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 6. 정규성검정 pvalue 확인하기
# result.pvalue를 round(..., 3)으로 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드: sample을 만든 뒤 shapiro pvalue를 round(..., 3)으로 출력하세요.

문제 7정규성 가정 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 7. 정규성 가정 확인하기
# result.pvalue가 0.05보다 큰지 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드: sample을 만든 뒤 shapiro pvalue를 0.05와 비교하세요.

개념

stats.ttest_1samp(): 한 집단 평균 비교

한 집단의 평균이 어떤 기준값과 다른지 보고 싶을 때 stats.ttest_1samp()를 사용합니다. popmean= 자리에 비교 기준값을 넣습니다.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

sample = df["악력D : kg"].sample(150, random_state=42)

two_sided = stats.ttest_1samp(sample, popmean=30)
greater = stats.ttest_1samp(sample, popmean=30, alternative="greater")
less = stats.ttest_1samp(sample, popmean=30, alternative="less")

print(round(two_sided.statistic, 3))
print(format(two_sided.pvalue, ".3e"))
print(format(greater.pvalue, ".3e"))
print(round(less.pvalue, 1))

실행 결과:

9.055
7.071e-16
3.536e-16
1.0

양측검정인 two_sided는 “다르다”를, greater는 “평균이 더 크다”를, less는 “평균이 더 작다”를 보는 방향입니다. 이 예시는 표본 평균이 30보다 큰 쪽이므로 greater의 pvalue가 아주 작고, 반대 방향인 less의 pvalue는 1.0에 가깝게 나옵니다.

alternative 파라미터는 초보자가 특히 자주 헷갈리는 부분입니다.

  • two-sided: 크든 작든 다르면 본다
  • greater: 표본 평균이 기준값보다 큰지 본다
  • less: 표본 평균이 기준값보다 작은지 본다
문제 8one-sample t검정 statistic 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 8. one-sample t검정 statistic 확인하기
# /data/body.csv의 악력D : kg 샘플 150개를 사용해 popmean=30으로 검정한 뒤 statistic을 round(..., 3)으로 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드: sample을 만든 뒤 stats.ttest_1samp(sample, popmean=30)을 실행하세요.

문제 9one-sample t검정 pvalue 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 9. one-sample t검정 pvalue 확인하기
# result.pvalue를 scientific notation으로 format(..., ".3e") 하여 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드: sample과 result를 만든 뒤 pvalue를 format(..., ".3e") 하세요.

문제 10greater 단측검정 pvalue 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 10. greater 단측검정 pvalue 확인하기
# alternative="greater"로 다시 검정한 뒤 pvalue를 format(..., ".3e")로 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드: sample을 만든 뒤 alternative="greater" 옵션으로 검정하세요.

개념

stats.ttest_ind(): 서로 다른 두 집단 비교

서로 독립인 두 집단의 평균 차이를 보고 싶을 때는 stats.ttest_ind()를 씁니다. 예를 들어 남성과 여성의 키 평균이 다른지 보고 싶다면 이 검정을 사용할 수 있습니다.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

male_height = df.loc[df["측정회원성별"] == "M", "신장 : cm"].sample(120, random_state=42)
female_height = df.loc[df["측정회원성별"] == "F", "신장 : cm"].sample(120, random_state=42)

result = stats.ttest_ind(male_height, female_height, equal_var=False)

print(round(result.statistic, 3))
print(format(result.pvalue, ".3e"))
print(result.pvalue < 0.05)

실행 결과:

17.726
3.539e-45
True

여기서는 pvalue가 매우 작아서 두 집단 평균 차이가 우연이라고 보기 어렵다는 뜻입니다. equal_var=False는 두 집단 분산이 같다고 강하게 가정하지 않는 Welch t-test 방식이라, 초보자가 안전하게 시작하기 좋습니다.

문제 11독립표본 t검정 statistic 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 11. 독립표본 t검정 statistic 확인하기
# male_height와 female_height의 독립표본 t검정 statistic을 round(..., 3)으로 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드
# 1. 측정회원성별이 M인 신장 : cm 120개를 male_height로 만드세요.
# 2. 측정회원성별이 F인 신장 : cm 120개를 female_height로 만드세요.
# 3. stats.ttest_ind(..., equal_var=False)의 statistic을 출력하세요.

문제 12독립표본 t검정 pvalue 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 12. 독립표본 t검정 pvalue 확인하기
# result.pvalue를 format(..., ".3e")로 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드
# 1. 문제 11과 같은 male_height, female_height를 만드세요.
# 2. stats.ttest_ind(..., equal_var=False)를 실행하세요.
# 3. pvalue를 format(..., ".3e")로 출력하세요.

문제 13두 집단 차이 여부 판단하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 13. 두 집단 차이 여부 판단하기
# result.pvalue가 0.05보다 작은지 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드
# 1. 남성과 여성의 신장 : cm 샘플을 각각 120개씩 만드세요.
# 2. 독립표본 t검정을 실행하세요.
# 3. pvalue를 0.05와 비교하세요.

개념

stats.ttest_rel(): 같은 짝의 전후 비교

같은 대상에서 전후를 비교하거나, 시점이 서로 짝지어진 두 값을 비교할 때는 stats.ttest_rel()을 사용합니다. 독립표본이 아니라 “쌍이 맞는 데이터”라는 점이 중요합니다.

import pandas as pd
from scipy import stats

data_path = "/data/weather.csv"

df = pd.read_csv(data_path)
paired = df[["이화동기온", "수영동기온"]].dropna().head(200)

two_sided = stats.ttest_rel(paired["이화동기온"], paired["수영동기온"])
less = stats.ttest_rel(paired["이화동기온"], paired["수영동기온"], alternative="less")
greater = stats.ttest_rel(paired["이화동기온"], paired["수영동기온"], alternative="greater")

print(round(two_sided.statistic, 2))
print(format(less.pvalue, ".3e"))
print(round(greater.pvalue, 1))

실행 결과:

-41.52
2.839e-100
1.0

통계량이 음수라는 것은 첫 번째 값인 이화동기온이 두 번째 값인 수영동기온보다 작은 방향이라는 뜻입니다. 그래서 alternative="less"의 pvalue는 아주 작고, 반대 방향인 greater의 pvalue는 1.0이 됩니다.

문제 14대응표본 t검정 statistic 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 14. 대응표본 t검정 statistic 확인하기
# /data/weather.csv의 앞 200행에서 이화동기온과 수영동기온의 대응표본 t검정 statistic을 round(..., 2)로 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/weather.csv"

df = pd.read_csv(data_path)

# 가이드
# 1. 이화동기온과 수영동기온 두 열만 골라 결측치를 제거하고 앞 200행을 사용하세요.
# 2. stats.ttest_rel()을 실행하세요.
# 3. statistic을 round(..., 2)로 출력하세요.

문제 15less 단측검정 pvalue 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 15. less 단측검정 pvalue 확인하기
# alternative="less"로 대응표본 t검정을 하고 pvalue를 format(..., ".3e")로 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/weather.csv"

df = pd.read_csv(data_path)

# 가이드
# 1. 짝지은 데이터 paired를 만드세요.
# 2. stats.ttest_rel(..., alternative="less")를 실행하세요.
# 3. pvalue를 format(..., ".3e")로 출력하세요.

문제 16greater 단측검정 pvalue 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 16. greater 단측검정 pvalue 확인하기
# alternative="greater"로 대응표본 t검정을 하고 pvalue를 round(..., 1)로 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/weather.csv"

df = pd.read_csv(data_path)

# 가이드
# 1. paired를 만든 뒤 stats.ttest_rel(..., alternative="greater")를 실행하세요.
# 2. pvalue를 round(..., 1)로 출력하세요.

개념

stats.f_oneway(): 세 집단 이상 비교하는 ANOVA

세 집단 이상 평균을 한 번에 비교할 때는 stats.f_oneway()를 사용합니다. 이것이 일원분산분석(ANOVA)입니다.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

group_a = df.loc[df["등급"] == "A", "앉아윗몸앞으로굽히기 : cm"].dropna().sample(200, random_state=42)
group_b = df.loc[df["등급"] == "B", "앉아윗몸앞으로굽히기 : cm"].dropna().sample(200, random_state=42)
group_c = df.loc[df["등급"] == "C", "앉아윗몸앞으로굽히기 : cm"].dropna().sample(200, random_state=42)

result = stats.f_oneway(group_a, group_b, group_c)

print(round(result.statistic, 3))
print(format(result.pvalue, ".3e"))
print(result.pvalue < 0.05)

실행 결과:

96.893
3.612e-37
True

이 결과는 세 집단 평균이 모두 같다고 보기 어렵다는 뜻입니다. 다만 ANOVA는 “어느 집단끼리 다른지”까지는 바로 알려 주지 않습니다. 그것까지 보려면 사후검정이 필요합니다. 초보자 단계에서는 “세 집단 이상이면 먼저 ANOVA를 생각한다” 정도로 익히면 좋습니다.

문제 17ANOVA statistic 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 17. ANOVA statistic 확인하기
# flexibility의 A, B, C 그룹으로 ANOVA를 한 뒤 statistic을 round(..., 3)으로 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드
# 1. 등급이 A, B, C인 앉아윗몸앞으로굽히기 : cm 값을 각각 200개씩 sample 하세요.
# 2. stats.f_oneway(group_a, group_b, group_c)를 실행하세요.
# 3. statistic을 round(..., 3)으로 출력하세요.

문제 18ANOVA pvalue 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 18. ANOVA pvalue 확인하기
# result.pvalue를 format(..., ".3e")로 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드
# 1. 문제 17과 같은 세 그룹을 만드세요.
# 2. ANOVA를 실행하세요.
# 3. pvalue를 format(..., ".3e")로 출력하세요.

문제 19ANOVA 결과 판단하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 19. ANOVA 결과 판단하기
# result.pvalue가 0.05보다 작은지 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드
# 1. 등급별 세 그룹을 만든 뒤 ANOVA를 실행하세요.
# 2. pvalue를 0.05와 비교하세요.

개념

pvalue를 결론 문장으로 바꾸기

초보자가 가장 자주 어려워하는 부분은 숫자를 결론 문장으로 바꾸는 단계입니다. 처음에는 아래처럼 아주 단순한 문장부터 만들면 됩니다.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

male_height = df.loc[df["측정회원성별"] == "M", "신장 : cm"].sample(120, random_state=42)
female_height = df.loc[df["측정회원성별"] == "F", "신장 : cm"].sample(120, random_state=42)

normality_result = stats.shapiro(male_height)
ttest_result = stats.ttest_ind(male_height, female_height, equal_var=False)

print("정규성 문제 없음" if normality_result.pvalue > 0.05 else "정규성 다시 확인")
print("차이가 있다" if ttest_result.pvalue < 0.05 else "차이가 없다")

실행 결과:

정규성 문제 없음
차이가 있다

이렇게 숫자를 바로 문장으로 바꾸는 연습을 해 두면, 이후 문제풀이와 보고서 작성이 훨씬 쉬워집니다. 물론 실제 실무에서는 더 조심스럽게 쓰지만, 입문 단계에서는 먼저 짧고 분명한 문장으로 바꾸는 연습이 중요합니다.

문제 20정규성 결과를 True/False로 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 20. 정규성 결과를 True/False로 확인하기
# male_height의 shapiro pvalue가 0.05보다 큰지 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드
# 1. 측정회원성별이 M인 신장 : cm 샘플 120개를 만드세요.
# 2. stats.shapiro()를 실행하세요.
# 3. pvalue를 0.05와 비교하세요.

문제 21두 집단 차이 결과를 True/False로 확인하기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 21. 두 집단 차이 결과를 True/False로 확인하기
# male_height와 female_height의 t검정 pvalue가 0.05보다 작은지 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드
# 1. 남성과 여성의 신장 : cm 샘플을 각각 만드세요.
# 2. stats.ttest_ind(..., equal_var=False)를 실행하세요.
# 3. pvalue를 0.05와 비교하세요.

문제 22결론 문장 만들기

에디터 로딩 중...

코드 입력 환경을 준비하고 있습니다.

# 문제 22. 결론 문장 만들기
# pvalue가 0.05보다 작으면 "차이가 있다", 아니면 "차이가 없다"를 출력해 보세요.

import pandas as pd
from scipy import stats

data_path = "/data/body.csv"

df = pd.read_csv(data_path)

# 가이드
# 1. 남성과 여성의 신장 : cm 샘플을 각각 120개씩 만드세요.
# 2. 독립표본 t검정을 실행하세요.
# 3. pvalue를 이용해 결론 문장을 출력하세요.