본문 바로가기
ML & DL/책 & 강의

[혼공머신] Chapter 05 트리 알고리즘

by 공부하는 무니 2023. 2. 5.
반응형

한빛미디어에서 모집하는 혼공학습단 활동의 일환으로 혼자 공부하는 머신러닝+딥러닝 책을 공부하고 정리한 글입니다. 책은 제 돈으로 구매했습니다. 원본 코드는 저자 박해선 님의 깃허브에서 보실 수 있습니다.

 

GitHub - rickiepark/hg-mldl: <혼자 공부하는 머신러닝+딥러닝>의 코드 저장소입니다.

<혼자 공부하는 머신러닝+딥러닝>의 코드 저장소입니다. Contribute to rickiepark/hg-mldl development by creating an account on GitHub.

github.com


Chapter 05 트리 알고리즘

05-1 결정 트리

로지스틱 회귀로 와인 분류하기

import pandas as pd

wine = pd.read_csv('https://bit.ly/wine_csv_data')

wine.head()

info 함수
데이터프레임의 각 열의 데이터 타입과 누락된 데이터가 있는지 확인하는 함수
wine.info()

describe 함수
열에 대한 간략한 통계를 출력해주는 함수
최소, 최대, 평균값 등을 볼 수 있다.

data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()

from sklearn.model_selection import train_test_split

train_input, test_input, train_target, test_target = train_test_split(
    data, target, test_size=0.2, random_state=42)
    
print(train_input.shape, test_input.shape)

from sklearn.preprocessing import StandardScaler

ss = StandardScaler()
ss.fit(train_input)

train_scaled = ss.transform(train_input)
test_scaled = ss.transform(test_input)

from sklearn.linear_model import LogisticRegression

lr = LogisticRegression()
lr.fit(train_scaled, train_target)

print(lr.score(train_scaled, train_target))
print(lr.score(test_scaled, test_target))

설명하기 쉬운 모델과 어려운 모델

print(lr.coef_, lr.intercept_)

결정 트리

from sklearn.tree import DecisionTreeClassifier

dt = DecisionTreeClassifier(random_state=42)
dt.fit(train_scaled, train_target)

print(dt.score(train_scaled, train_target))
print(dt.score(test_scaled, test_target))

import matplotlib.pyplot as plt
from sklearn.tree import plot_tree

plt.figure(figsize=(10,7))
plot_tree(dt)
plt.show()

노드
노드는 결정 트리를 구성하는 핵심 요소이다.
훈련 데이터의 특성에 대한 테스트를 표현한다.

가지
가지는 테스트의 결과(True, False)를 나타내며, 일반적으로 하나의 노드는 2개의 가지를 가진다.
plt.figure(figsize=(10,7))
plot_tree(dt, max_depth=1, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

불순도

지니 불순도(Gini impurity)
DecisionTreeClassifier클래스의 criterion 파라미터의 디폴트 값
critreion 파라미터: 노드에서 데이터를 분할할 기준을 정하는 것
지니 불순도 = 1 - (음성 클래스 비율^2 + 양성 크래스 비율^2 )
만약 100개의 샘플이 있는 노드의 두 클래스의 비율이 정확히 1/2로 50개씩 있다면 지니 불순도는 최악으로 0.5가 된다.
만약 노드에 하나의 클래스만 있다면 지니 불순도는 0이 된다.(이런 노드를 순수 노드라고 함)

결정 트리 모델은 부모 노드와 자식 노드의 불순도 차이가 가능한 크도록 트리를 성장시킨다. 
정보 이득(information gain)
결정 트리 모델은 부모 노드와 자식 노드의 불순도 차이가 가능한 크도록 트리를 성장시킨다. 
불순도의 차이 = 부모의 불순도 - (왼쪽 노드 샘플 수 / 부모의 샘플 수)*왼쪽 노드 불순도 - (오른쪽 노드 샘플 수 / 부모의 샘플 수)*오른쪽 노드 불순도
이러한 부모와 자식 노드 사이의 불순도 차이를 정보 이득이라고 부른다.
엔트로피 불순도
DecisionTreeClassifier클래스의 또다른 criterion. criterion='entropy'를 지정하면 된다. 
엔트로피 불순도는 밑이 2인 로그를 사용하여 곱한다. 
-음성 클래스 비율*log2(음성 클래스 비율) - 양성 클래스 비율*log2(양성 클래스 비율)

가지치기

dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(train_scaled, train_target)

print(dt.score(train_scaled, train_target))
print(dt.score(test_scaled, test_target))

plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(train_input, train_target)

print(dt.score(train_input, train_target))
print(dt.score(test_input, test_target))

plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()

print(dt.feature_importances_)

05-2 교차 검증과 그리드 서치

검증 세트

import pandas as pd

wine = pd.read_csv('https://bit.ly/wine_csv_data')

data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()

from sklearn.model_selection import train_test_split

train_input, test_input, train_target, test_target = train_test_split(
    data, target, test_size=0.2, random_state=42)
    
sub_input, val_input, sub_target, val_target = train_test_split(
    train_input, train_target, test_size=0.2, random_state=42)
    
print(sub_input.shape, val_input.shape)

from sklearn.tree import DecisionTreeClassifier

dt = DecisionTreeClassifier(random_state=42)
dt.fit(sub_input, sub_target)

print(dt.score(sub_input, sub_target))
print(dt.score(val_input, val_target))

교차 검증

k-폴드 교차 검증(k-fold cross validation)
훈련 세트를 k개의 부분으로 나눠서 교차 검증을 수행하는 것. k-겹 교차 검증이라고도 부름
from sklearn.model_selection import cross_validate

scores = cross_validate(dt, train_input, train_target)
print(scores)

import numpy as np

print(np.mean(scores['test_score']))

from sklearn.model_selection import StratifiedKFold

scores = cross_validate(dt, train_input, train_target, cv=StratifiedKFold())
print(np.mean(scores['test_score']))

splitter = StratifiedKFold(n_splits=10, shuffle=True, random_state=42)
scores = cross_validate(dt, train_input, train_target, cv=splitter)
print(np.mean(scores['test_score']))

하이퍼파라미터 튜닝

from sklearn.model_selection import GridSearchCV

params = {'min_impurity_decrease': [0.0001, 0.0002, 0.0003, 0.0004, 0.0005]}

gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1)

gs.fit(train_input, train_target)

dt = gs.best_estimator_
print(dt.score(train_input, train_target))

print(gs.best_params_)

print(gs.cv_results_['mean_test_score'])

best_index = np.argmax(gs.cv_results_['mean_test_score'])
print(gs.cv_results_['params'][best_index])

params = {'min_impurity_decrease': np.arange(0.0001, 0.001, 0.0001),
          'max_depth': range(5, 20, 1),
          'min_samples_split': range(2, 100, 10)
          }
          
gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1)
gs.fit(train_input, train_target)

print(gs.best_params_)

print(np.max(gs.cv_results_['mean_test_score']))

랜덤 서치

from scipy.stats import uniform, randint

rgen = randint(0, 10)
rgen.rvs(10)

np.unique(rgen.rvs(1000), return_counts=True)

ugen = uniform(0, 1)
ugen.rvs(10)

params = {'min_impurity_decrease': uniform(0.0001, 0.001),
          'max_depth': randint(20, 50),
          'min_samples_split': randint(2, 25),
          'min_samples_leaf': randint(1, 25),
          }
          
from sklearn.model_selection import RandomizedSearchCV

gs = RandomizedSearchCV(DecisionTreeClassifier(random_state=42), params, 
                        n_iter=100, n_jobs=-1, random_state=42)
gs.fit(train_input, train_target)

print(gs.best_params_)

print(np.max(gs.cv_results_['mean_test_score']))

dt = gs.best_estimator_

print(dt.score(test_input, test_target))

05-3 트리의 앙상블

정형 데이터와 비정형 데이터

정형 데이터 structured data
어떤 구조로되어 있는 데이터.
CSV, 데이터베이스, 엑셀 에 저장하기 쉽다
정형 데이터를 다루는 데 가장 뛰어난 성과를 내는 알고리즘이 앙상블 학습이다.
비정형 데이터 unstructured data
데이터베이스나 엑셀로 표현하기 어려운 것들
책의 글과 같은 텍스트 데이터, 사진, 디지털 음악 등
비정형 데이터에는 신경망 알고리즘이 좋다.

랜덤 포레스트

부트스트랩 방식
데이터 세트에서 중복을 허용하여 데이터를 샘플링하는 방식
부트스트랩 샘플은 부트스트랩 방식으로 샘플링하여 분류한 데이터
랜덤 포레스트
부트스트랩 샘플 사용. 대표 앙상블 학습 알고리즘
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split

wine = pd.read_csv('https://bit.ly/wine_csv_data')

data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['class'].to_numpy()

train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2, random_state=42)

from sklearn.model_selection import cross_validate
from sklearn.ensemble import RandomForestClassifier

rf = RandomForestClassifier(n_jobs=-1, random_state=42)
scores = cross_validate(rf, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

rf.fit(train_input, train_target)
print(rf.feature_importances_)

rf = RandomForestClassifier(oob_score=True, n_jobs=-1, random_state=42)

rf.fit(train_input, train_target)
print(rf.oob_score_)

엑스트라 트리

엑스트라 트리
결정 트리의 노드를 랜덤하게 분할
from sklearn.ensemble import ExtraTreesClassifier

et = ExtraTreesClassifier(n_jobs=-1, random_state=42)
scores = cross_validate(et, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

et.fit(train_input, train_target)
print(et.feature_importances_)

그레이디언트 부스팅

그래이디언트 부스팅
이진 트리의 손실을 보완하는 식으로 얕은 결정 트리를 연속하여 추가함
from sklearn.ensemble import GradientBoostingClassifier

gb = GradientBoostingClassifier(random_state=42)
scores = cross_validate(gb, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

gb = GradientBoostingClassifier(n_estimators=500, learning_rate=0.2, random_state=42)
scores = cross_validate(gb, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

gb.fit(train_input, train_target)
print(gb.feature_importances_)

히스토그램 기반 그레이디언트 부스팅

히스토그램 기반 그레이디언트 부스팅
훈련 데이터를 256개 정수 구간으로 나누어 빠르고 높은 성능을 냄
from sklearn.ensemble import HistGradientBoostingClassifier

hgb = HistGradientBoostingClassifier(random_state=42)
scores = cross_validate(hgb, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

from sklearn.inspection import permutation_importance

hgb.fit(train_input, train_target)
result = permutation_importance(hgb, train_input, train_target, n_repeats=10,
                                random_state=42, n_jobs=-1)
print(result.importances_mean)

 

result = permutation_importance(hgb, test_input, test_target, n_repeats=10,
                                random_state=42, n_jobs=-1)
print(result.importances_mean)

hgb.score(test_input, test_target)

XGBoost

from xgboost import XGBClassifier

xgb = XGBClassifier(tree_method='hist', random_state=42)
scores = cross_validate(xgb, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

LightGBM

from lightgbm import LGBMClassifier

lgb = LGBMClassifier(random_state=42)
scores = cross_validate(lgb, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

혼공머신 미션

기본 미션 - 교차 검증을 그림으로 설명하기

 

선택 미션 - Ch.05(05-3) 앙상블 모델 손코딩 코랩 화면 인증하기

반응형

댓글