혼공학습단/혼자 공부하는 데이터 분석 with 파이썬

[혼공분석] #7. 검증하고 예측하기

✨️데이터분석가✨️ 2024. 2. 12. 20:41
728x90
728x90
7. 검증하고 예측하기
    1) 통계적으로 추론하기

        (1) 모수검정
        (2) 표준점수
        (3) 표준정규분포
        (4) 중심극한정리
        (5) 신뢰구간
        (6) 가설검정 
        (7) 순열검정
    2) 머신러닝으로 예측하기
        (1) 머신러닝 용어
        (2) 선형 회귀 모델 훈련
        (3) 결정계수
        (4) 선형 회귀
        (5) 로지스틱 회귀

 

1) 통계적으로 추론하기

(1) 모수검정

- 모집단에서 추출한 샘플(표본)로부터 모집단의 파라미터(평균/분산)를 추정하는 방법

- 모수검정은 모집단이 어떤 가정이다를 전제로 수행되는 경우가 많음 (예, 정규분포를 따름)

 

 


(2) 표준점수 (= z 점수)

- 정규분포 상에서 각 값이 평균에서 얼마나 떨어져 있는지를 표준편차를 사용해 변환한 점수 [z=(x-평균)/표준편차]

- z 점수 구하는 2가지 방법이며, ①넘파이 / ②사이파이의 stats 모듈의 [zscore() 함수]

import numpy as np
x = [0, 3, 5, 7, 10]
s = np.std(x)
m = np.mean(x)
z = (7 - m) / s
print(z)
 
from scipy import stats
stats.zscore(x)
 
0.5872202202195147035
array([-1.46805055, -0.58722022,  0.        ,  0.58722022,  1.46805055])

 

 


(3) 표준정규분포

- 평균 0, 표준편차가 1인 좌우 대칭인 정규분포

- z 점수가 2 이내에 위치한 샘플은 전체의 약 95% 해당 (z 점수 1 이내의 비율은 약 68%)

- [norm.cdf() 메서드]로 특정 값 까지의 누적분포를 구할 수 있음

- [norm.ppf() 메서드]로 특정 비율 까지의 누적분포를 구할 수 있음

stats.norm.cdf(2.0) - stats.norm.cdf(-2.0)
stats.norm.ppf(0.975)
 
0.9544997361036416
1.959963984540054

 

 


(4) 중심극한정리

- 무작위로 샘플을 뽑아 표본의 평균을 구하는 작업을 여러 번 반복하면 정규분포에 가까워진다는 이론 (n은 30이상)

- [sample() 메서드]로 무작위로 30개씩 샘플링하여 [mean() 메서드]로 각 평균을 저장

- 1000번 반복하면 종 모양과 유사한 분포를 보임

np.random.seed(42)
sample_means = []
for _ in range(1000):
    m = ns_book7['대출건수'].sample(30).mean()
    sample_means.append(m)
plt.hist(sample_means, bins=30)
plt.show()

중심극한정리
중심극한정리

 

- 표준오차는 표본 평균의 표준편차로(=모딥단 표준편차/샘플 개수), 표본으로 계산한 표준편차 값과 유사한 편임

np.std(ns_book7['대출건수']) / np.sqrt(30)
np.std(sample_means)
 
3.5199178205234167
3.444642892473277

 

 


(5) 신뢰구간

- 표본평균을 이용하여 모평균이 포함될 가능성이 있다고 추정하는 구간 (일반적으로 95% 신뢰구간 사용)

- 주제분류번호가 '00'이면서 도서명에 '파이썬'이 포함된 도서 대출건수의 신뢰구간 구하기

- 중심극한정리를 적용하여 표본의 표준편차로 표준오차 계산, 95% 이내 구간에서 모집단 평균을 계산함

→ 모집단의 평균이 13.2~16.3에 있을 확률이 95%다. (= 95% 신뢰구간에서 모집단 평균은 13.2~16.3에 있다.)

python_books_index = ns_book7['주제분류번호'].str.startswith('00') & ns_book7['도서명'].str.contains('파이썬')
python_books = ns_book7[python_books_index]
python_mean = np.mean(python_books['대출건수'])
python_std = np.std(python_books['대출건수'])
python_se = python_std / np.sqrt(len(python_books))
print(python_mean-1.96*python_se, python_mean+1.96*python_se)
 
13.172848017867965     16.325158850259522

 

 

 


(6) 가설검정

- 표본 정보로 모집단에 대한 가설을 채택할지 기각할지 결정하는 방법

  * 귀무가설(=영가설) Ho: 통계적으로 의미가 없다고 예상되는 가설

  * 대립가설 H : 표본 사이에 통계적인 차이가 있다는 가설

 

① z 점수로 가설검정

- C++ 도서와 파이썬 도서의 평균 대출건수 차이가 있는지 검증하기

- 두 모집단의 평균에 대한 z 점수 공식 z = (모집단1 평균 - 모집단2 평균) / sqrt(모집단1 표준오차²+모집단2 표준오차²)

- 누적분포는 0.994, 정규분포 양쪽 끝 면적은 각 0.006, p-값은 0.01로 유의수준 0.05보다 작아 귀무가설이 기각됨

→ C++ 도서와 파이썬 도서의 평균 대출건수에 차이가 있다

(python_mean - cplus_mean) / np.sqrt(python_se**2 + cplus_se**2)
2.495408195140708
 
stats.norm.cdf(2.50)
0.9937903346742238
 
p_value = (1-0.994)*2
0.0120000000000001

 

② t-검정으로 가설검정

- [ttest_ind() 함수]는 t-분포인 두 표본을 비교하는 t-검정을 수행함

t, pvalue = stats.ttest_ind(python_books['대출건수'], cplus_books['대출건수'])
print(t, pvalue)
 
2.1390005694958574     0.03315179520224784

 

 


(7) 순열검정

- 모집단의 분포가 정규분포를 따르지 않거나, 분포를 알 수 없을 때 사용하는 검정 방법 (비모수검정)

- 두 표본의 데이터를 무작위로 섞어 나눈 다음 원래 통계량과의 차이를 비교하는 과정을 여러 번 반복함

- 두 배열을 [append() 함수]로 합친 후, [permutation() 함수]로 랜덤 추출하여 x_, y_ 두 그룹 사이의 평균 차이를 계산하는 과정을 1000번 반복

- 일반적으로 귀무가설 기각이 목적이므로 둘 중에 작은 값을 선택하고 2를 곱해 양쪽 꼬리에 해당하는 비율을 계산

→ p-값은 0.02로 유의수준 0.05보다 작으므로, 두 도서의 평균 대출건수에는 차이가 있다

def statistic(x, y):     # 두 표본의 평균 차이를 계산
    return np.mean(x) - np.mean(y)
def permutation_test(x, y):
    obs_diff = statistic(x, y)
    all = np.append(x, y)     # 두 표본을 합침
    diffs = []
    np.random.seed(42)
    for _ in range(1000):     # 순열검정 1000번 반복
        idx = np.random.permutation(len(all))     # 전체 인덱스를 섞음
        x_ = all[idx[:len(x)]]     # 랜덤하게 두 그룹으로 나눔
        y_ = all[idx[len(x):]]
        diffs.append(statistic(x_, y_))     # 평균 차이 계산
    less_pvalue = np.sum(diffs < obs_diff)/1000     # 원본 표본보다 작거나 큰 경우의 p-값을 계산
    greater_pvalue = np.sum(diffs > obs_diff)/1000
    return obs_diff, np.minimum(less_pvalue, greater_pvalue) * 2     # 둘 중 작은 p-값에 2를 곱해 최종 p-값을 반환
permutation_test(python_books['대출건수'], cplus_books['대출건수'])
 
(3.1534983660862164, 0.022)

 

 

 


 

2) 머신러닝으로 예측하기

(1) 머신러닝 용어

모델: 머신러닝으로 훈련된 프로그램 객체

사이킷런: 파이썬의 대표적인 머신러닝 패키지 (scikit-learn) 

지도학습: 데이터에 있는 각 샘플에 대한 정답(타깃)을 알고 있는 경우

                 입력과 타깃으로 모델을 훈련한 후, 타깃을 모르는 새로운 입력에 모델을 적용하여 타깃을 예측하는 것

비지도학습: 입력 데이터는 있지만 타깃이 없는 경우 (예, 군집 알고리즘)

훈련 세트: 모델을 훈련하기 위해 사용하는 데이터 (데이터량: 훈련 > 테스트)

테스트 세트: 훈련된 모델을 평가하기 위해 사용하는 데이터

 

 


(2) 선형 회귀 모델 훈련

[train_test_split() 함수]로 훈련(75%) 및 테스트(25%) 세트로 데이터를 나눔

from sklearn.model_selection import train_test_split
train_set, test_set = train_test_split(ns_book7, random_state=42)
print(len(train_set), len(test_set))
 
282577 94193

 

- '도서권수' 열은 리스트로 감싸서 저장하여 2차원 배열로 만듬

- 사이킷런이 입력으로는 2차원 배열, 타깃은 1차원 배열을 기대하며, 2차원 배열은 대문자로 표시하는 관례가 있음

X_train = train_set[['도서권수']]
y_train = train_set['대출건수']
print(X_train.shape, y_train.shape)
 
(282577, 1) (282577,)

 

- [linear_model 모듈][LinearRegression 클래스]로 선형 회귀 모델을 훈련

- LinearRegression 클래스의 객체 lr을 만들고, 이 객체의 [fit() 메서드]에 입력/타깃 데이터를 전달하여 훈련함

from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(X_train, y_train)
 
LinearRegression()

 

 


(3) 결정계수: 회귀 모델 평가

[score() 메서드]로 산출된 값은 결정계수로, 훈련된 머신러닝 모델이 얼마나 유용한지 평가함

- 보통 0~1 값을 가지며, 예측이 타깃의 평균에 가까우면 0, 예측이 정확하면 1에 가까움

X_test = test_set[['도서권수']]
y_test = test_set['대출건수']
lr.score(X_test, y_test)
 
0.10025676249337112

 

 


(4) 선형 회귀: 연속적인 값 예측

- 선형 회귀 알고리즘은 y = ax+b 방정식임 (x는 입력, y는 타깃)

[coef_속성]은 기울기, [intercept_속성]은 절편이 저장됨

→ 기울기는 1, 절편은 0에 가까운 매우 작은 음수

print(lr.coef_, lr.intercept_)
 
[1.]     -3.907985046680551e-14

 

 


(5) 로지스틱 회귀: 카테고리 예측

- 분류 알고리즘, 두 개의 카테고리로 구분하면 이진 분류, 세 개 이상은 다중 분류라고 함

- 선형 함수의 결과값 z를 로지스틱 함수에 통과시키면 y = 0~1 값, y > 0.5이면 양성 클래스로 예측함 (y < 0.5는 음성)

- 평균 대출건수보다 높은 훈련/테스트 데이터를 양성 클래스(1)로 변환함

- [LogisticRegresstion 클래스]로 로지스틱 모델을 훈련, 훈련 세트는 [fit() 메서드], 테스트 세트는 [score() 메서드]로 호출함

→ 정확도(score() 메서드가 출력하는 점수)는 71%로 무난한 결과임 (입력 데이터 중 정답을 맞힌 비율)

borrow_mean = ns_book7['대출건수'].mean()
y_train_c = y_train > borrow_mean
y_test_c = y_test > borrow_mean

from sklearn.linear_model import LogisticRegression
logr = LogisticRegression()
logr.fit(X_train, y_train_c)
logr.score(X_test, y_test_c)
 
0.7106154385145393

 

- [DummyClassifier 모델]은 분류에서 가장 많은 클래스를 예측으로 출력함 (회귀는 DummyRegressor 모델)

→ 정확도는 69%로 이 값이 모델을 만들 때 기준점이 됨 (최소 이 값보다 낮다면, 유용한 모델이라고 할 수 없음)

from sklearn.dummy import DummyClassifier
dc = DummyClassifier()
dc.fit(X_train, y_train_c)
dc.score(X_test, y_test_c)
 
0.6936502712515792

 

 

 

728x90
728x90