'누구나 파이썬 통계분석' p.294
## 문제상황
- 편의점 감자튀김(무게 130g)
- 무게 하나 잼. 122.02g
- 2주간 매일 감자튀김 무게 잼
+ 14개 표본의 평균 = 128.451g
## 질문
- 어떤 통계 검정 방법을 사용해야 할까?
+ t-test, one sample t-test
+ 표본 14개 ==> 정규성 검정 진행 후, 통과할때 one sample t-test
- 귀무가설과 대립가설을 설정해보세요
+ 귀무가설 : 모평균(130g)과 표본평균(128.451g)과 같다
+ 대립가설 : 모평균과 표본평균은 같지 않다. (양측검정)
+ 대립가설 : 모평균 > 포본평균 (단측검정)
# 기본코드
!pip install scipy
import scipy
scipy.__version__ # 버전확인
import numpy as np
import pandas as pd
from scipy import stats
%precision 3
np.random.seed(1111)
%precision 3 이 명령어는 숫자 출력의 소수점 이하 자릿수를 설정하는 데 사용됩니다. 여기서 3은 소수점 이하 세 자리까지 표시하도록 설정된 것을 의미한다.
np.random.seed(1111) NumPy 라이브러리에서 난수 발생을 제어하기 위한 메서드
이 메서드는 난수 생성 알고리즘에 초기 시드 값을 제공하여, 같은 시드를 사용하면 항상 같은 난수 시퀀스가 생성되도록 한다. 따라서 np.random.seed(1111)은 난수 생성기를 시드 값 1111로 초기화하는 역할을 한다.
df = pd.read_csv('data/data/ch11_potato.csv')
sample = np.array(df['무게'])
sample
'''결과
array([122.02, 131.73, 130.6 , 131.82, 132.05, 126.12, 124.43, 132.89,
122.79, 129.95, 126.14, 134.45, 127.64, 125.68])'''
# 표본평균
s_mean = np.mean(sample)
s_mean
'''결과
128.451
'''
학생의 관심
- 14개 표본평균이 모평균(130g) 보다 작은지 여부
- 감자튀김의 표본집단이 정규분포를 따르고 있고(정규성 검정 할 필요 없음)
- 비모수 검정을 쓸 필요가 없다
- 모수 검정 실시
- 모분산이 9임을 알고 있다고 전제
rv = stats.norm(130, # 모평균, rv(임계값)
np.sqrt(9/14)) # 9 모분산, 14 표본의 개수
rv.isf(0.95) # 0.95 신뢰구간 95%
'''
결과
128.681
'''
z = (s_mean-130) / np.sqrt(9/14)
z # 검정통계량 / t-통계량
검정통계량/ t-통계량인 z의 값은 -1.932 이다.
# 검정 통계량에 관한 임계값을 구하기
rv = stats.norm()
rv.isf(0.95)
'''
결과
-1.645
'''
rv.cdf(z) # 유의수준 0.05보다 작음
# 귀무가설 : 모평균 130g == 표본평균 128.451g
# 대립가설 : 모평균 != 표본평균
# 대립가설 채택을 한다는 말은 통계에서는 존재하지 않음 / 귀무가설 채택 or 기각(=대립가설채택)
'''
결과
0.027
'''
# 양측검정
z = (s_mean-130)/np.sqrt(9/14)
rv = stats.norm()
rv.interval(0.95) # 신뢰구간 95%
'''
결과
(-1.960, 1.960)
'''
양측검정의 p값을 구할 때는 상단과 하단의 양쪽 면적을 고려할 필요가 있으므로 누적밀도함수의 값을 2배로 한다.
rv.cdf(z)*2 # p value
'''
결과
0.053
'''
p값이 유의수준 0.05보다 크므로 귀무가설은 기각되지 않는다.
질문
- 단측검정, 양측검정을 어떤 상황에서 구분해서 사용하나요
- 양측검정 A와 B가 Not Same
- 단측검정 A>B , B>A
가설검정의 두 가지 오류
- 제 1종 오류 : 귀무가설이 옳을 때 귀무가설을 기각하는 오류
- 제 2종 오류 : 대립가설이 옳을 때 귀무가설을 채택하는 오류
제 1종 오류
- 실제로 평균이 130g인데도 평균은 130g보다 작다고 결론을 내리는 상황
- False Positive (오탐)
모집단의 확률분포는 N(130,3^2)
rv = stats.norm(130,3)
이 모집단에서 14개의 표본을 표출하여 가설검정을 수행하는 작업을 10000번 한다. 제1종 오류(평균이 130g인데도 평균은 130g보다 작다라는 결론을 내림)를 범하는 비율 계산
c = stats.norm().isf(0.95)
n_samples = 10000
cnt = 0
for _ in range(n_samples):
sample_ = np.round(rv.rvs(14), 2)
s_mean_ = np.mean(sample_)
z = (s_mean_ - 130) / np.sqrt(9/14)
if z < c:
cnt += 1
cnt / n_samples
'''
결과
0.053
'''
- 1종 오류를 범할 비율은 0.053 / 약 5%의 비율로 130g보다 작다고 잘못 탐지하는 것
- 1종 오류를 범할 확률(위험률)
- 엄격하게 적용하고 싶으면 유의수준 1%에서 가설검정을 수행
제 2종 오류
- 실제로 표본평균이 130g 보다 작음에도 불구하고 표본평균은 130g보다 작다라는 결론을 얻을 수 없는 상황
- 본래 검출해야 하는 것을 검출하지 못했으므로 미탐 false negative 이라고도 함
만약 학생이 감자튀김 평균이 128g이라고 잘못 알고 있는 경우 모집단의 확률분포로 N(128,3^2)로 알고 있을 것이다.
rv = stats.norm(128, 3) # 학생이 얻은 들은 정보 : 실제로는 평균이 128g이라더라
c = stats.norm().isf(0.95)
n_samples = 10000
cnt = 0
for _ in range(n_samples):
sample_ = np.round(rv.rvs(14), 2)
s_mean_ = np.mean(sample_)
z = (s_mean_ - 130) / np.sqrt(9/14)
if z >= c:
cnt += 1
cnt / n_samples
'''
결과
0.197
'''
대략 20%의 비율로 미탐이 발생함. 제2종 오류는 모집단의 정보에 의존한다. 분석가는 모집단의 정보를 원래는 알 수 없는 것이므로 분석가가 제어할수 없는 확률이다.
통계적 가설검정에서는 제1종 오류는 제어할 수 있지만, 제2종 오류는 제어할 수 없는 비대칭성이 있다.
모분산을 모르는 경우
def pmean_test(sample, mean0, alpha=0.05):
'''
sample : 표본 샘플 데이터
mean0 : 모평균을 제안 (감자칩의 무게와 같이 이미 기 제안이 된 것)
alpha : 신뢰구간 95% 수준의 신뢰구간
'''
s_mean = np.mean(sample)
u_var = np.var(sample, ddof=1)
n = len(sample)
rv = stats.t(df=n-1)
interval = rv.interval(1-alpha)
t = (s_mean - mean0) / np.sqrt(u_var/n)
print(f't통계량 값: {t:3f}')
if interval[0] <= t <= interval[1]:
print('귀무가설을 채택')
else:
print('귀무가설을 기각')
if t < 0:
p = rv.cdf(t) * 2
else:
p = (1 - rv.cdf(t)) * 2
print(f'p값은 {p:.3f}')
pmean_test(sample,130)
'''
결과
t통계량 값: -1.455196
귀무가설을 채택
p값은 0.169
'''
1표본 t 검정은 scipy.stats에 ttest_1samp 함수로 구현되어 있다. 이 함수의 반환값은 t(검정통계량)과 p값이다.
t,p = stats.ttest_1samp(sample,130)
t,p
'''
결과
(-1.455, 0.169)
'''
모분산을 안다
- 현실적으로 모집단을 아는 것은 불가능
- 모분산을 알고 있다는 뜻은 모집단을 알고 있다 => 모평균도 구할 수 있음 => 모평균에 대한 검정을 우리가 굳이 할 필요가 있나?