vmtmxmf5 / Python-ML-DNN

4 stars 1 forks source link

머딥 - 12d (앙상블 모델, voting, bagging, boosting, stacking) #42

Open vmtmxmf5 opened 3 years ago

vmtmxmf5 commented 3 years ago

앙상블 모델

데이터 로드

import numpy as np
import pandas as pd

from sklearn.datasets import load_boston

data = load_boston()

df = pd.DataFrame(
    data['data'],
    columns=data['feature_names'])

df['MEDV'] = data['target']

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
    df.drop('MEDV', axis=1),
    df['MEDV'],
    random_state=42
    )

평가지표

from sklearn.metrics import mean_absolute_error, mean_squared_error

import matplotlib.pyplot as plt
import seaborn as sns
my_predictions = {}
colors = ['r', 'c', 'm', 'y', 'k', 'khaki', 'teal', 'orchid', 'sandybrown',
          'greenyellow', 'dodgerblue', 'deepskyblue', 'rosybrown', 'firebrick',
          'deeppink', 'crimson', 'salmon', 'darkred', 'olivedrab', 'olive', 
          'forestgreen', 'royalblue', 'indigo', 'navy', 'mediumpurple', 'chocolate',
          'gold', 'darkorange', 'seagreen', 'turquoise', 'steelblue', 'slategray', 
          'peru', 'midnightblue', 'slateblue', 'dimgray', 'cadetblue', 'tomato'
         ]
def plot_predictions(name_, pred, actual):
    df = pd.DataFrame({'prediction': pred, 'actual': y_test})
    df = df.sort_values(by='actual').reset_index(drop=True)
    plt.figure(figsize=(12, 9))
    plt.scatter(df.index, df['prediction'], marker='x', color='r')
    plt.scatter(df.index, df['actual'], alpha=0.7, marker='o', color='black')
    plt.title(name_, fontsize=15)
    plt.legend(['prediction', 'actual'], fontsize=12)
    plt.show()
def mse_eval(name_, pred, actual):
    global predictions
    global colors
    plot_predictions(name_, pred, actual)
    mse = mean_squared_error(pred, actual)
    my_predictions[name_] = mse
    y_value = sorted(my_predictions.items(), key=lambda x: x[1], reverse=True)
    df = pd.DataFrame(y_value, columns=['model', 'mse'])
    print(df)
    min_ = df['mse'].min() - 10
    max_ = df['mse'].max() + 10
    length = len(df)
    plt.figure(figsize=(10, length))
    ax = plt.subplot()
    ax.set_yticks(np.arange(len(df)))
    ax.set_yticklabels(df['model'], fontsize=15)
    bars = ax.barh(np.arange(len(df)), df['mse'])
    for i, v in enumerate(df['mse']):
        idx = np.random.choice(len(colors))
        bars[i].set_color(colors[idx])
        ax.text(v + 2, i, str(round(v, 3)), color='k', fontsize=15, fontweight='bold')
    plt.title('MSE Error', fontsize=18)
    plt.xlim(min_, max_)
    plt.show()
def remove_model(name_):
    global my_predictions
    try:
        del my_predictions[name_]
    except KeyError:
        return False
    return True
def plot_coef(columns, coef):
    coef_df = pd.DataFrame(list(zip(columns, coef)))
    coef_df.columns=['feature', 'coef']
    coef_df = coef_df.sort_values('coef', ascending=False).reset_index(drop=True)
    fig, ax = plt.subplots(figsize=(9, 7))
    ax.barh(np.arange(len(coef_df)), coef_df['coef'])
    idx = np.arange(len(coef_df))
    ax.set_yticks(idx)
    ax.set_yticklabels(coef_df['feature'])
    fig.tight_layout()
    plt.show()
from sklearn.linear_model import LinearRegression, Ridge, Lasso, ElasticNet

lin = LinearRegression()
lin.fit(X_train, y_train)
pred = lin.predict(X_test)
mse_eval("LinearRegression", pred, y_test)

ridge = Ridge(alpha=1)
ridge.fit(X_train, y_train)
pred = ridge.predict(X_test)
mse_eval('RidgeRegression', pred, y_test)

lasso = Lasso(alpha=0.01)
lasso.fit(X_train, y_train)
pred = lasso.predict(X_test)
mse_eval('LassoRegression', pred, y_test)

elastic = ElasticNet(alpha=0.5 ,l1_ratio=0.5)
elastic.fit(X_train, y_train)
pred = elastic.predict(X_test)
mse_eval('ElasticNetRegression',pred, y_test)

voting : 투표를 통해 결과를 도출

서로 다른 오차를 독립적으로 만들 가능성이 높을 수록 결과가 좋다

"(y - y_hat)"이 가장 작은 값을 뽑은 모델의 "(y - y_hat)"만 모아서 새로운 mse 계산

다른 알고리즘을 조합해서 사용

from sklearn.ensemble import VotingRegressor, VotingClassifier

반드시 Tuple 형태로 만들어야 함

single_model = [
    ('lin_reg', lin),
    ('ridge', ridge),
    ('lasso', lasso),
    ('elas', elastic)
]

voting_regressor = VotingRegressor(
    single_model,
    n_jobs=-1
)

voting_regressor.fit(X_train, y_train)
voting_pred = voting_regressor.predict(X_test)
mse_eval('Voting Ensemble', voting_pred, y_test)

voting={'hard', 'soft'}

hard voting은 [1, 1, 1, 0, 0]으로 예측이 되면 다수 클래스인 1을 채택(결과)

soft voting 모델마다 각 클래스가 나올 확률의 값을 계산해서, 각 y_hat마다 모델들의 특정 클래스가 나올 평균 확률을 비교해서 클래스를 정한다.

각각의 확률들은 독립적인 모델들의 확률이기 때문에 평균을 낸 값들을 더해도 반드시 1이 된다

from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import VotingClassifier

models = [
    ('logistic', LogisticRegression()),
    ('svc', SVC())]

vc = VotingClassifier(models, voting='hard')
vc = VotingClassifier(models, voting='soft')

bagging : 샘플 중복 생성을 통해 결과 도출

같은 알고리즘 내에서 다른 샘플 조합을 사용

scaling 필요없고 bootstrapping도 있으므로 nan값 예측에 써도 된다

from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier

rfr = RandomForestRegressor()
rfr.fit(X_train, y_train)
rfr_pred = rfr.predict(X_test)
mse_eval('RandomForest', rfr_pred, y_test)

from sklearn.ensemble import BaggingRegressor

bag_reg = BaggingRegressor(base_estimator=Lasso())
bag_reg.fit(X_train, y_train)
bag_reg_pred = bag_reg.predict(X_test)
mse_eval('BaggingRegressor', bag_reg_pred, y_test)

boosting : 이전 오차를 보완하면서 가중치를 부여함

outlier에 민감하다. 왜? 오분류를 보완하기 위해 가중치를 부여하기 때문에

overfitting 걱정은 ㄴㄴ. 복잡도가 일정 정도 올라가다가 거의 수렴해버림

AdaBoost : 적응형 부스팅. learning rate 자동조절.

y가 패턴 없이 분포해있을 때 안전한 모델링 방법

from sklearn.ensemble import AdaBoostClassifier, AdaBoostRegressor

ada = AdaBoostRegressor(random_state=42)
ada.fit(X_train, y_train)
ada_pred = ada.predict(X_test)
mse_eval('Adaboost', ada_pred, y_test)

GradientBoost : 점점 강해지는 부스팅

from sklearn.ensemble import GradientBoostingClassifier, GradientBoostingRegressor

gbr = GradientBoostingRegressor(random_state=42)
gbr.fit(X_train, y_train)
gbr_pred = gbr.predict(X_test)
mse_eval('GradientBoost', gbr_pred, y_test)

LightGBM

from lightgbm import LGBMRegressor, LGBMClassifier

lgbm = LGBMRegressor(random_state=42)
lgbm.fit(X_train, y_train)
lgbm_pred = lgbm.predict(X_test)
mse_eval('LGBMregressor', lgbm_pred, y_test)

XGBoost : GBM보다 빠르고 성능 향상, 평가방식에 e를 수식에 넣음

from xgboost import XGBRegressor

xgb = XGBRegressor(random_state=42)
xgb.fit(X_train, y_train)
xgb_pred = xgb.predict(X_test)
mse_eval('XGBoost', xgb_pred, y_test)

stacking : 여러 모델을 기반으로 예측된 결과를 통해 meta모델이 다시 한번 예측

linear_yhat 열, lasso_yhat 열, ridge_yhat 열을 각각 feature 처럼 취급해서 final_estimatorh pred 를 계산하는 방법

개별 모델이 예측한 데이터를 기반으로 final_estimator가 종합해서 예측을 수행한다

overfitting 가능성이 있다

from sklearn.ensemble import StackingClassifier, StackingRegressor

stack_models = [
    ('rf', rfr),
    ('gbr', gbr),
    ('lgbm', lgbm)
    ]

stack_reg = StackingRegressor(stack_models, final_estimator=xgb, n_jobs=-1)
stack_reg.fit(X_train, y_train)
stack_pred = stack_reg.predict(X_test) 
mse_eval('stacking', stack_pred, y_test)

Weighted Blending (모델이 아님, 하이퍼파라미터임)

각 모델의 y_hat 에 가중치를 곱해서 최종 output을 계산한다

= 모델에 가중치를 조정 := elastic net

=> 모든 가중치의 합은 1.0

final_outputs = {
    'elasticnet' : pred,
    'randomforest': rfr_pred,
    'gbr': gbr_pred,
    'xgb': xgb_pred,
    'lgbm': lgbm_pred,
    'stacking': stack_pred
    }

final_pred = final_outputs['elasticnet'] * 0.1 \
    + final_outputs['randomforest'] * 0.2 \
    + final_outputs['gbr'] * 0.15\
    + final_outputs['xgb'] * 0.25\
    + final_outputs['lgbm'] * 0.1\
    + final_outputs['stacking'] * 0.2

mse_eval('weighted blending', final_pred, y_test)
vmtmxmf5 commented 3 years ago

voting 독립적인 분류기들이 서로 다른 오차를 줄인다 bagging 부트스트랩을 사용해 모델간의 상관관계를 줄여 분산을 감소시킨다

rf = RandomForestClassifier()
lr = LogisticRegression()
svc = SVC(probability=True)

voting_clf = VotingClassifier(
    estimators=[('lr', lr),
                ('rf', rf),
                ('svc', svc)],
    voting='soft'
    )