독립성 검정
- 변수가 두개 이상 범주로 분할되어 있고, 독립적인지 연관성이 있는지 검정
- 귀무가설(H0) : 서로 독립
- 대립가설(H1) : 연관성이 있다
- p-value < 0.05 이면 대립가설 채택
검정방법 순서
- 패키지 추가 (from scipy.stats import chi2_contingency)
- 데이터 table 변환 (범주형 - pd.crosstab / 수치형 - np.array)
- chi2 검정 (chi2, p_val, dof(자유도), ex(기대치))
패키지
from scipy.stats import chi2_contingency
from statsmodels.formula.api import logit
독립성 검정
import pandas as pd
df = pd.read_csv("data/Titanic.csv")
#1번 문제
from scipy.stats import chi2_contingency
table = pd.crosstab(df.Gender, df.Survived)
chi2, p_val, dof, exp = chi2_contingency(table)
print(round(chi2, 3)) # 260.717
print(p_val) # 매우 작으므로 대립가설 채택
로지스틱 회귀
from statsmodels.formula.api import logit
result1 = logit('Survived ~ Gender+SibSp+Parch+Fare', data=df).fit().summary()
print(result1)
오즈비 구하기
import numpy as np
result2 = logit('Survived ~ Gender+SibSp+Parch+Fare', data=df).fit().params
print(np.exp(result2))
상관계수
df.corr()
Shapiro-Wilk (정규분포)
from scipy import stats
statistic, p_val = stats.shapiro(data)
출처 - datamanim.com
stats 주요 모듈
01 T-test
- ttest_1samp (단일표본 t검정)
- ttest_ind (독립표본 t검정)
- ttest_rel (대응표본 t검정)
02 비모수 검정
- manwhitneyu (맨-휘트니 U검정-중위수, 윌콕슨 순위합 검정과 동일)
- ranksums (윌콕슨 순위합 검정 - 중위수)
- wilcoxon (윌콕슨 부호 순위합 검정)
03 정규성 검정
- anderson (Anderson-Darling, 데이터 수가 상대적으로 많을 때)
- kstest (Kolmogorov-smirnov, 데이터 수가 상대적으로 많을 때)
- mstats.normaltest
- shapiro (shapiro, 노말분포, 데이터 수가 상대적으로 적을 때)
04 등분산 검정
05 카이제곱 검정
- chi2_contingency (카이제곱독립검정, 독립성 검정)
- chisquare (카이제곱검정, 적합도 검정)
- fisher_exact (피셔 정확 검정 - 빈도수가 5개 이하 셀의 수가 전체 셀의 20%이상일 경우)
06 ANOVA (일원분산분석)
예시
#1 정규성 검정
01 다음 데이터의 정규성을 검증하라
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/normal1.csv')
from scipy.stats import shapiro
print(shapiro(df))
- 결과
ShapiroResult(statistic=0.9981444478034973, pvalue=0.34849318861961365)
-> 통계랑이 1에 가까우므로 정규분포에 가까움
-> p-value가 0.05보다 크므로 귀무가설 기각X -> 정규 분포를 따름
-> 통계량이 1에 가깝더라도, p-value가 0.05보다 작으면 정규성X
02 다음 데이터를 log변환 후 정규성을 확인하라
import pandas as pd
import numpy as np
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/normal3.csv')
log_df = np.log1p(df)
from scipy.stats import shapiro
print(shapiro(log_df))
- 결과
ShapiroResult(statistic=0.9976889491081238, pvalue=0.17540602385997772)
-> 0.05보다 크므로 정규성 O
-> log변환 시 너무 작은 값이거나, 0, 음수를 포함하는 값들이 있을때 사용
03 다음 데이터의 정규성을 검증하라
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/normal6.csv')
from scipy.stats import shapiro
#shapiro(df)
from scipy.stats import anderson
anderson(df['data'].values)
- 결과
AndersonResult(statistic=0.8266993530405671, critical_values=array([0.576, 0.656, 0.786, 0.917, 1.091]), significance_level=array([15. , 10. , 5. , 2.5, 1. ]), fit_result= params: FitParams(loc=299.95980319533163, scale=5.031806887885131)
success: True
message: 'anderson
successfully fit the distribution to the data.')
-> 5000개 이상일 경우 shapiro 말고 anderson 사용
-> 5% : 0.786 < 통계량 : 0.827 < 2.5% : 0.917
-> 따라서 유의수준 5% 이하이므로, 정규성 X
#2 단일 표본 t검정(one-sample)
01 100명의 키 정보가 들어있는 데이터가 있다. 데이터가 정규성을 만족하는지 확인하라. 그리고 평균키는 165라 판단할 수 있는지 귀무가설과 대립가설을 설정한 후 유의수준 5%로 검정하라
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/height1.csv')
from scipy.stats import shapiro
shapiro(df)
# ShapiroResult(statistic=0.9872668981552124, pvalue=0.4558176100254059)
# 정규성 O -> 단일 표본 t 검정
from scipy.stats import ttest_1samp
ttest_1samp(df['height'], 165)
- 결과
TtestResult(statistic=3.2017884987150644, pvalue=0.0018367171548080209, df=99)
-> p-value 0.05이하 이므로, 100명 키의 평균은 165가 아니다.
02 100명의 키 정보가 들어있는 데이터가 있다. 데이터가 정규성을 만족하는지 확인하라. 그리고 평균키는 165라 판단할 수 있는지 귀무가설과 대립가설을 설정한 후 유의수준 5%로 검정하라
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/height2.csv')
from scipy.stats import shapiro
shapiro(df)
# ShapiroResult(statistic=0.9672006368637085, pvalue=0.013552471995353699)
# 정규성 X -> 비모수 검정 (윌콕슨)
from scipy.stats import wilcoxon
wilcoxon(df)
- 결과
WilcoxonResult(statistic=array([0.]), pvalue=array([3.87726172e-18]))
-> p-value가 0.05보다 작으므로, 대립가설 채택
-> 100명 키의 평균은 165가 아니다.
#3 등분산 검정
01 두 개 학급의 시험성적에 대한 데이터이다. 그룹간 등분산 검정을 시행하라.
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/scipy2.csv')
from scipy.stats import bartlett
from scipy.stats import fligner
from scipy.stats import levene
a = df[df['class'] == 'A'].score
b = df[df['class'] == 'B'].score
print(bartlett(a, b))
print(fligner(a, b, center = 'median'))
print(fligner(a, b, center = 'mean'))
print(levene(a, b, center = 'median'))
print(levene(a, b, center = 'mean'))
- 결과
BartlettResult(statistic=0.26035880448930865, pvalue=0.609873758447687)
FlignerResult(statistic=0.7281251154135562, pvalue=0.39349158741002765)
FlignerResult(statistic=0.8272211734319945, pvalue=0.36307728836821906)
LeveneResult(statistic=0.3145466542912649, pvalue=0.5751662820554713)
LeveneResult(statistic=0.5086970687685527, pvalue=0.4760514837800255)
-> 0.05보다 크므로, 각 그룹은 등분산이다.
02 두 개 학급의 시험성적에 대한 데이터이다. 그룹간 등분산 검정을 시행하라.
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/scipy3.csv')
from scipy.stats import bartlett
from scipy.stats import fligner
from scipy.stats import levene
a = df[df['class'] =='A'].score
b = df[df['class'] =='B'].score
print(bartlett(a,b))
print(fligner(a,b,center='median')) #default
print(fligner(a,b,center='mean'))
print(levene(a,b, center='median')) #default
print(levene(a,b,center='mean'))
- 결과
BartlettResult(statistic=1.5116783794562305, pvalue=0.2188831590902503)
FlignerResult(statistic=4.960366756026232, pvalue=0.025934706256615564)
FlignerResult(statistic=4.94724457924667, pvalue=0.026132286002684912)
LeveneResult(statistic=4.307122424591436, pvalue=0.03848734007752694)
LeveneResult(statistic=4.342327020297874, pvalue=0.0377066528874248)
-> fligner, levene 는 bartlett에 비해 robust하다
-> 정규분포를 따르지 않는다면 bartlett은 신뢰하기 어렵다
-> 따라서 등분산 X
03 두 개 학급의 시험성적에 대한 데이터이다. 그룹간 등분산 검정을 시행하라.
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/scipy6.csv')
from scipy.stats import bartlett
from scipy.stats import fligner
from scipy.stats import levene
print(bartlett(df.A, df.B))
print(fligner(df.A, df.B))
print(levene(df.A, df.B))
- 결과
BartlettResult(statistic=2.3832178811043527, pvalue=0.12264468401745829)
FlignerResult(statistic=5.124831619122788, pvalue=0.023585858890699054)
LeveneResult(statistic=5.147914610463281, pvalue=0.023868975493455683)
04 두 개 학급의 시험성적에 대한 데이터이다. 그룹간 등분산 검정을 시행하라.
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/scipy5.csv')
print(bartlett(df.A, df.B.dropna()))
print(fligner(df.A, df.B.dropna()))
print(levene(df.A, df.B.dropna()))
- 결과
BartlettResult(statistic=3.024072692680794, pvalue=0.08203720607748438)
FlignerResult(statistic=7.710320541528441, pvalue=0.005490600130793619)
LeveneResult(statistic=8.008595918808284, pvalue=0.004851565077063284)
-> nan 값이 포함될 경우 없애고 등분산 검정을 시행해야 한다
#4 독립 표본 검정(Independent) - 정규성에 따라 다름
01 두 개 학급의 시험성적에 대한 데이터이다. 두 학급의 시험 평균(비모수검정의 경우 중위값)은 동일하다 말할 수 있는지 확인하라.
import pandas as pd
df1 = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/ind1.csv')
df2 = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/ind2.csv')
from scipy.stats import shapiro
print(shapiro(df1)) # 정규성 O
print(shapiro(df2)) # 정규성 O
from scipy.stats import levene
print(levene(df1['data'], df2['data'])) # 등분산 O
from scipy.stats import ttest_ind
print(ttest_ind(df1, df2, equal_var = True))
- 결과
ShapiroResult(statistic=0.9860946536064148, pvalue=0.379673033952713)
ShapiroResult(statistic=0.990182638168335, pvalue=0.6793646216392517)
LeveneResult(statistic=2.5337683795339547, pvalue=0.11302904824469093)
TtestResult(statistic=array([2.76719074]), pvalue=array([0.00619015]), df=array([198.]))
-> 대립가설 채택
-> 각 그룹 평균은 동일하지 않다
02 두 개 학급의 시험성적에 대한 데이터이다. 두 학급의 시험 평균(비모수검정의 경우 중위값)은 동일하다 말할 수 있는지 확인하라.
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/scipy5.csv')
from scipy.stats import shapiro
print(shapiro(df.A)) # 정규성 X
print(shapiro(df.B.dropna())) # 정규성 X
from scipy.stats import mannwhitneyu, ranksums
print(mannwhitneyu(df.A, df.B.dropna())) # 귀무가설 채택
print(ranksums(df.A, df.B.dropna())) # 귀무가설 채택
- 결과
ShapiroResult(statistic=0.93753981590271, pvalue=6.175894240456614e-10)
ShapiroResult(statistic=0.9639433026313782, pvalue=0.00013568344002123922)
MannwhitneyuResult(statistic=27036.0, pvalue=0.9807458376150018)
RanksumsResult(statistic=0.02446942170858557, pvalue=0.9804781743503561)
-> 귀무가설 채택
-> 평균은 같다
03 두개 그룹에 대한 수치형 데이터이다. 두 그룹은 평균이 동일하다 말할 수 있는가
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/ind3.csv')
from scipy.stats import shapiro
a = df[df['group'] == 'a'].data
b = df[df['group'] == 'b'].data
print(shapiro(a)) # 정규성 O
print(shapiro(b)) # 정규성 O
from scipy.stats import levene
print(levene(a, b)) # 등분산 X
from scipy.stats import ttest_ind
print(ttest_ind(a, b, equal_var = False))
- 결과
ShapiroResult(statistic=0.9834123253822327, pvalue=0.1473984718322754)
ShapiroResult(statistic=0.9831852316856384, pvalue=0.4701973497867584)
LeveneResult(statistic=6.185601018015722, pvalue=0.013750484571911342)
TtestResult(statistic=-2.1949470315829265, pvalue=0.029512802991767898, df=171.25282465005142)
-> 귀무가설 기각
-> 평균 동일 X
04 두개 그룹에 대한 수치형 데이터이다. 두 그룹은 평균이 동일하다 말할 수 있는가
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/ind6.csv')
from scipy.stats import shapiro
print(shapiro(df.a)) # 정규성 O
print(shapiro(df.b.dropna())) # 정규성 O
from scipy.stats import levene
print(levene(df.a, df.b.dropna())) # 등분산 X
from scipy.stats import ttest_ind
print(ttest_ind(df.a, df.b.dropna(), equal_var = False))
- 결과
ShapiroResult(statistic=0.9865895509719849, pvalue=0.28390026092529297)
ShapiroResult(statistic=0.9854326844215393, pvalue=0.5937624573707581)
LeveneResult(statistic=3.9862856894158347, pvalue=0.04731495612868527)
TtestResult(statistic=0.0015963310698567184, pvalue=0.9987289046092704, df=122.72255248639058)
-> 귀무가설 기각X
-> 평균값은 동일
#5 대응 표본 t 검정 (paired)
01 특정 질병 집단의 투약 전후의 혈류량 변화를 나타낸 데이터이다. 투약 전후의 변화가 있는지 검정하라
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/rel2.csv')
from scipy.stats import shapiro
print(shapiro(df.before)) # 정규성 O
print(shapiro(df.after)) # 정규성 O
from scipy.stats import levene
print(levene(df.before, df.after)) # 등분산 O
from scipy.stats import ttest_rel
print(ttest_rel(df.before, df.after))
- 결과
ShapiroResult(statistic=0.9907895922660828, pvalue=0.6065835952758789)
ShapiroResult(statistic=0.9916961193084717, pvalue=0.6923638582229614)
LeveneResult(statistic=0.06427968690211128, pvalue=0.8000741651677987)
TtestResult(statistic=-2.5535473487670677, pvalue=0.011926744724546513, df=119)
-> p-value 0.05이내
-> 대립가설 채택
-> 평균은 같지 않다
02 특정 질병 집단의 투약 전후의 혈류량 변화를 나타낸 데이터이다. 투약 전후의 변화가 있는지 검정하라
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/rel3.csv')
from scipy.stats import shapiro
print(shapiro(df.before)) # 정규성 O
print(shapiro(df.after)) # 정규성 O
from scipy.stats import levene
print(levene(df.before, df.after)) # 등분산 O
from scipy.stats import ttest_rel
print(ttest_rel(df.before, df.after))
- 결과
ShapiroResult(statistic=0.9920631051063538, pvalue=0.7270199656486511)
ShapiroResult(statistic=0.992019534111023, pvalue=0.7229290008544922)
LeveneResult(statistic=1.3463330638203617, pvalue=0.24708279045237214)
TtestResult(statistic=0.188900575991026, pvalue=0.8504925317234707, df=119)
-> 귀무가설 채택
-> 평균은 같다
03 특정 집단의 학습 전후 시험 성적 변화를 나타낸 데이터이다. 시험 전과 후에 차이가 있는지 검정하라.
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/rel1.csv')
from scipy.stats import shapiro
print(shapiro(df.before)) # 정규성 X
print(shapiro(df.after)) # 정규성 X
from scipy.stats import levene
print(levene(df.before, df.after)) # 등분산 O
from scipy.stats import wilcoxon
print(wilcoxon(df.before, df.after))
- 결과
ShapiroResult(statistic=0.9173730611801147, pvalue=0.0018974003614857793)
ShapiroResult(statistic=0.9448966979980469, pvalue=0.021140215918421745)
LeveneResult(statistic=0.14329522146179022, pvalue=0.7058456563194881)
WilcoxonResult(statistic=437.0, pvalue=0.12098409484052809)
-> p-value 0.05보다 높으므로, 귀무가설 채택
-> 전 후 평균 일치
04 한 기계 부품의 rpm 수치를 두 가지 다른 상황에서 측정했다. (총 70세트) b상황이 a상황보다 rpm값이 높다고 말할 수 있는지 검정하라.
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/rel4.csv')
a = df[df['group'] == 'a'].rpm
b = df[df['group'] == 'b'].rpm
from scipy.stats import shapiro
print(shapiro(a)) # 정규성 O
print(shapiro(b)) # 정규성 O
from scipy.stats import levene
print(levene(a, b)) # 등분산 O
from scipy.stats import ttest_rel
print(ttest_rel(a, b, alternative = 'greater'))
- 결과
ShapiroResult(statistic=0.9907217025756836, pvalue=0.8884284496307373)
ShapiroResult(statistic=0.984674870967865, pvalue=0.5505106449127197)
LeveneResult(statistic=0.06716114122680159, pvalue=0.7959020864923277)
TtestResult(statistic=-1.9018108294460812, pvalue=0.9693143365355352, df=69)
-> a>b 가 대립가설, a<=b 가 귀무가설
-> 0.05보다 크므로 귀무가설 채택
#6 카이제곱 검정 (교차분석)
01 144회 주사위를 던졌을 때, 각 눈금별로 나온 횟수를 나타낸다. 이 데이터는 주사위의 분포에서 나올 가능성이 있는지 검정하라
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/dice.csv')
from scipy.stats import chisquare
df['expected'] = (df['counts'].sum()/6).astype('int')
print(chisquare(df.counts, df.expected))
- 결과
Power_divergenceResult(statistic=2.333333333333333, pvalue=0.8013589222076911)
-> 귀무가설 채택
-> 각 주사위 눈금 발생 비율은 동일함
02 다음 데이터는 국민 기초체력을 조사한 데이터이다. 성별과 등급이 독립적인지 검정하라.
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/body/body.csv')
cdf = pd.crosstab(df['측정회원성별'], df['등급'])
from scipy.stats import chi2_contingency
chi2, p, dof, exp = chi2_contingency(cdf)
print(p)
- 결과
7.481892813401677e-26
-> 귀무가설 기각
-> 두 항목은 연관이 있다
03 성별에 따른 동아리 활동 참석 비율을 나타낸 데이터이다. 성별과 참석간에 관련이 있는지 검정하라.
import pandas as pd
df = pd.read_csv('https://raw.githubusercontent.com/Datamanim/datarepo/main/scipy/fe2.csv',index_col=0)
cdf = df.iloc[:-1, :-1]
from scipy.stats import chi2_contingency
chi2, p, dof, exp = chi2_contingency(cdf)
print(p) # 귀무가설 채택 -> 하지만 5보다 작은 셀이 20%가 넘어가므로 피셔의 정확검정을 사용해야함
from scipy.stats import fisher_exact
print(fisher_exact(cdf))
- 결과
0.07023259819117404
SignificanceResult(statistic=18.0, pvalue=0.03571428571428571)
-> 대립가설 채택
-> 관련이 있다