본문 바로가기
AI 공부/머신러닝

(머신러닝) 앙상블

by AI Sonny 2022. 9. 13.
728x90

기존 타이타닉 데이터를 이용하여 앙상블을 진행하겠다.

 

데이터 가져오기

 

import pandas as pd
import numpy as np
import seaborn as sns
from sklearn.preprocessing import OneHotEncoder
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score
df = sns.load_dataset('titanic') # 타이타닉 데이터 받아오기
cols = ["age","sibsp","parch","fare"] # 숫자니까 바로 사용
features = df[cols] # 피쳐
target = df["survived"] # 정답값
# one hot encoding
cols = ["pclass","sex","embarked"] # 범주형
enc = OneHotEncoder(handle_unknown='ignore')
tmp = pd.DataFrame(
    enc.fit_transform(df[cols]).toarray(),
    columns = enc.get_feature_names_out()
)
features = pd.concat([features,tmp],axis=1)
# 나이 결측치 채우기
features.age = features.age.fillna(features.age.median())

 

스케일링

 

from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()

features.loc[:,features.columns] = scaler.fit_transform(features) # 넘파이 형식에서 데이터프레임 형식으로 변환

 

마지막에 loc를 이용하여 넘파이 형식을 데이터프레임 형태로 바꾸었다.

 

SEED = 42

x_train,x_valid,y_train,y_valid = train_test_split(features,target,random_state=SEED,test_size=0.2)
x_train.shape,x_valid.shape,y_train.shape,y_valid.shape

=> ((712, 13), (179, 13), (712,), (179,))

 

학습데이터와 정답데이터를 분리하였다.

 

앙상블 학습(Ensemble Learning)

  • 기계학습에서 여러개의 개별 모델의 예측을 결함으로써 보다 정확한 예측을 도출하는 기법
 

앙상블 모델

 

Random Forest

  • 랜덤하게 일부 샘플들과 일부 피쳐들을 뽑아서 여러 개의 트리를 만들어서 앙상블하는 모델
  • 배깅 방식을 이용
  • 배깅(Bagging)
    • Bootstrap Aggregation의 약어
    • 샘플을 랜덤하게 여러번 뽑아 각 모델에 학습시켜 결과물을 집계하는 방법

 

from sklearn.ensemble import RandomForestClassifier

hp = {
    "random_state" : SEED,
    "max_features" : "sqrt", # None을 줄 경우 전체피쳐 사용
    "n_estimators" : 100, # 트리개수를 의미 (잘 기억해두기)
    "max_depth" : 10,
    "min_samples_split" : 10,
    "min_samples_leaf" : 3
}
model = RandomForestClassifier(**hp)
model.fit(x_train,y_train)
pred = model.predict_proba(x_valid)[:,1]
roc_auc_score(y_valid,pred)

=> 0.8952380952380953

 

배깅 적용 후

 

from sklearn.ensemble import BaggingClassifier
from sklearn.linear_model import LogisticRegression

hp = {
    "random_state" : SEED,
    "base_estimator" : LogisticRegression(random_state=SEED), # None이면 결정트리를 사용함
    "n_estimators" : 100, # base_estomator 개수
    "max_features" : 0.5 # 추출할 샘플 비율
}
model = BaggingClassifier(**hp)
model.fit(x_train,y_train)
pred = model.predict_proba(x_valid)[:,1]
roc_auc_score(y_valid,pred)

=> 0.8698841698841698

 

Voting

  • 여러 모델들의 예측값을 투표방식(hard) or 평균방식(soft)으로 앙상블

 

soft 방식

 

from sklearn.neural_network import MLPClassifier
from sklearn.ensemble import VotingClassifier

estimators = [
    ( "mlp",MLPClassifier(max_iter=1000,random_state=SEED) ),
    ( "lr", LogisticRegression(random_state=SEED) ),
    ( "rf", RandomForestClassifier(random_state=SEED) )
]

hp = {
    "estimators" : estimators,
    "voting" : "soft"
}
model = VotingClassifier(**hp)
model.fit(x_train,y_train)
pred = model.predict_proba(x_valid)[:,1]
roc_auc_score(y_valid,pred)

=> 0.9063063063063064

 

각 예측값을 평균낸다.

 

hard 방식

 

from sklearn.metrics import f1_score
from sklearn.neural_network import MLPClassifier
from sklearn.ensemble import VotingClassifier

estimators = [
    ( "mlp",MLPClassifier(max_iter=1000,random_state=SEED) ), # 0과 1의 과반수
    ( "lr", LogisticRegression(random_state=SEED) ),
    ( "rf", RandomForestClassifier(random_state=SEED) )
]

hp = {
    "estimators" : estimators,
    "voting" : "hard"
}
model = VotingClassifier(**hp)
model.fit(x_train,y_train)
pred = model.predict(x_valid)
f1_score(y_valid,pred) # 0과 1로 결정된 값

=> 0.7659574468085106

 


Stacking

  • 여러 모델들의 예측값을 최종모델(메타모델)의 학습 데이터로 사용해서 예측하는 방법
  • 과적합 방지하기 위해 내부적으로 CV를 진행한다.
from sklearn.ensemble import StackingClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier

estimators = [
    ( "knn",KNeighborsClassifier(n_neighbors=10,weights="distance") ),
    ( "dt", DecisionTreeClassifier(max_depth=3,random_state=SEED) ),
    ( "rf", RandomForestClassifier(random_state=SEED) )
]

hp = {
    "estimators" : estimators,
    "final_estimator" : LogisticRegression(random_state=SEED)
}

model = StackingClassifier(**hp,n_jobs = -1) # n_job -1 = cpu를 전부 다 사용하여 빠르게 나오도록한다. 있으면 무조건 사용
model.fit(x_train,y_train)
pred = model.predict_proba(x_valid)[:,1]
roc_auc_score(y_valid,pred)

=> 0.8820463320463321

 


GradientBoosting

  • 트리기반 부스팅 앙상블 모델
  • 머신러닝 알고리즘 중에서 가장 예측성능이 높다고 알려졌고, 인기있는 알고리즘

- Boosting

  • 약한 모델을 결합하여 강한 모델을 만드는 과정
  • 배깅과 다른점은 순차적으로 모델을 만들어 각 모델의 예측결과를 결합

 

혹시 모르니 데이터 복사해놓기 (튜플형태로 복사됨!)

 

data_backup = x_train.copy(), x_valid.copy(), y_train.copy(), y_valid.copy()

 

from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.metrics import mean_squared_error
from sklearn.datasets import load_diabetes
diabetes = load_diabetes()
data = diabetes.data
target = diabetes.target

data.shape, target.shape

=> ((442, 10), (442,))

 

데이터 셋 분리

 

x_train,x_valid,y_train,y_valid = train_test_split(data,target,random_state=SEED)
x_train.shape,x_valid.shape,y_train.shape,y_valid.shape

=> ((331, 10), (111, 10), (331,), (111,))

 

GradientBoostingRegressor 구현
 
hp = {
    "max_depth" : 2,
    "random_state" : SEED
}
weak_1 = DecisionTreeRegressor(**hp)
weak_1.fit(x_train,y_train)
pred = weak_1.predict(x_train)

 

residual = y_train - pred

weak_2 = DecisionTreeRegressor(**hp)
weak_2.fit(x_train,residual)
pred = weak_2.predict(x_train)

 

residual = residual - pred

weak_3 = DecisionTreeRegressor(**hp)
weak_3.fit(x_train,residual)

 

pred = weak_1.predict(x_valid) + weak_2.predict(x_valid) + weak_3.predict(x_valid)
mean_squared_error(y_valid,pred) ** 0.5 # RMSE

위 과정은 그냥 구현한 것이고, 밑에는 GradientBoostingRegressor를 사용하여 구현한 것이다.

 

그래서 결과값이 같다.

 

gbr = GradientBoostingRegressor(max_depth=2,random_state=SEED,n_estimators=3,learning_rate=1.) # 위와 같은 조건을 넣어줌!
gbr.fit(x_train,y_train)
pred = gbr.predict(x_valid)
mean_squared_error(y_valid,pred) ** 0.5

=> 61.872491186086826

 

- 복사한 타이타닉 데이터 복원하기

 

x_train, x_valid, y_train, y_valid = data_backup

 

from sklearn.ensemble import GradientBoostingClassifier

hp = {
    "random_state" : SEED,
    "max_depth" : 2,
    "n_estimators" : 100, # 수행할 부스팅 단계 수
}
model = GradientBoostingClassifier(**hp)
model.fit(x_train,y_train)
pred = model.predict_proba(x_valid)[:,1]
roc_auc_score(y_valid,pred)

=> 0.8911196911196911

 


XGBoost

  • 병렬처리가 불가능한 GBM의 단점을 보완
  • GPU를 지원
  • 내장된 교차검증과 결측치 처리같은 부가기능도 있다.
  • GBM보다 속도가 향상
  • 과적합 방지를 GBM보다 더 뛰어나게 방지한다.
  • https://xgboost.readthedocs.io/en/stable/
from xgboost import XGBClassifier,plot_importance
hp = {
    "random_state" : SEED,
    "max_depth" : 2,
    "n_estimators" : 100, # 수행할 부스팅 단계수
}

model = XGBClassifier(**hp)
model.fit(x_train,y_train)
pred = model.predict_proba(x_valid)[:,1]
roc_auc_score(y_valid,pred)

=> 0.8868082368082368

 

시각화

import matplotlib.pyplot as plt
plot_importance(model)
plt.show()

 

from xgboost import to_graphviz
to_graphviz(model)

 

 


LightGBM (많이 사용)

 

from lightgbm import LGBMClassifier, plot_importance
hp = {
    "random_state" : SEED,
    "max_depth" : 2,
    "n_estimators" : 100, # 수행할 부스팅 단계 수
}

model = LGBMClassifier(**hp)
model.fit(x_train,y_train)
pred = model.predict_proba(x_valid)[:,1]
roc_auc_score(y_valid,pred)

=> 0.8821106821106821

 

시각화

 

plot_importance(model)
plt.show()

 

from lightgbm import create_tree_digraph
create_tree_digraph(model)

 


catboost

  • 범주형 변수에 대하여 강력한 성능을 보여주는 GBM 기반 모델 
  • 범주형 변수가 많을 경우 높은 성능과 함께 속도가 lightgbm 보다 빠르다.
  • 수치형 변수가 많을 경우 매우 느림
  • 특징으로 범주형 변수를 인코딩 하지 않고 넣어도 된다.
  • https://catboost.ai/en/docs/

 

코랩에서는 catboost가 없어서 설치해야한다.

!pip install catboost

 

from catboost import CatBoostClassifier

hp = {
    "random_state" : SEED,
    "max_depth" : 2,
    "n_estimators" : 100, # 수행할 부스팅 단계 수
    "verbose" : 0 # 부스팅 단계 출력 안보이게 하기
}

model = CatBoostClassifier(**hp)
model.fit(x_train,y_train)
pred = model.predict_proba(x_valid)[:,1]
roc_auc_score(y_valid,pred)

=> 0.8787001287001287

 

catboost는 높은 성능과 함께 속도가 lightgbm 보다 빠르기 때문에

 

수치형을 범주형으로 변경해서 넣으면 좋을 수도 있다.


앙상블을 보고, 다양한 모델들을 각자 합리적인 방법으로 적용시키는 것이 신기하였다.

 

이것도 각 특징을 잘 알고, 잘써야겠다는 생각이 들었다.

728x90

'AI 공부 > 머신러닝' 카테고리의 다른 글

(머신러닝) 비지도 학습 - 차원축소  (1) 2022.09.14
(머신러닝) 모델튜닝  (1) 2022.09.13
(머신러닝) 머신러닝 모델  (2) 2022.09.13
(머신러닝) sklearn  (0) 2022.09.11
(머신러닝) 교차검증과 과적합  (0) 2022.09.07

댓글