본문 바로가기
ML | DL | Big data/Projects

kaggle 주택 가격 예측(4) - 모델 앙상블으로 등수 올리기(상위 13%)

by 썽하 2020. 8. 21.

저번 글에는 regression 4종으로 예측해보고, 결과가 가장나은 ElasticNet의 결과로 제출 해보았다.

이번글에는 조금더 핫하고 자주쓰이는 모델 중 LightGBM, XGBoost, GradientBoost 그리고 꼽사리로 RandomForest와 앙상블 기법으로 등수를 올려보자.

 


 

 

 

 

 

 

 

 

 

prediction with ensemble algorithms

 

임포팅, 데이터 로딩

In [1]:
# Imports
import pandas as pd
import numpy as np
from sklearn.model_selection import cross_val_score, train_test_split, KFold
from sklearn.preprocessing import StandardScaler, RobustScaler
from sklearn.linear_model import LinearRegression, RidgeCV, LassoCV, ElasticNetCV
from sklearn.metrics import mean_squared_error, make_scorer
from IPython.display import display
import matplotlib.pyplot as plt

import warnings
def ignore_warn(*args, **kwargs): pass
warnings.warn = ignore_warn #ignore annoying warning (from sklearn and seaborn)

%matplotlib inline

pd.set_option('display.float_format', lambda x: '%.3f' % x)
pd.set_option('display.max_colwidth', -1)
pd.set_option('display.max_rows', 500)
In [2]:
# 데이터 읽어오기
# 이전 글에서 데이터 전처리를 잘 따라왔다면 해당경로에 데이터가 저장되어 있을것이다.
# 동일한 데이터가 아니더라도 똑같은 포맷이라면 동일한 방식으로 사용해 볼 수 있다.
X_train = pd.read_csv("../data/X_train.csv", index_col=0, header=0)
X_test = pd.read_csv("../data/X_test.csv", index_col=0, header=0)
y_train = pd.read_csv("../data/y_train.csv", header=None, index_col = 0).values[:, 0]
Id_test = pd.read_csv("../data/Id_train.csv",  index_col=0, header=None).values[:, 0]
print(X_train.shape)
print(X_test.shape)
print(y_train.shape)
print(Id_test.shape)
 
(1458, 333)
(1459, 333)
(1458,)
(1459,)
 

Ensembel Modeling

 
  • GradientBoostingRegressor
  • XGBRegressor
  • LGBMRegressor
  • RandomForest

네 가지에 대해서 모델을 돌리고 평가해보자.

In [3]:
#Validation function
n_folds = 5

def rmsle_cv(model):
    kf = KFold(n_folds, shuffle=True, random_state=42).get_n_splits(X_train.values)
    rmse= np.sqrt(-cross_val_score(model, X_train.values, y_train, scoring="neg_mean_squared_error", cv = kf))
    return(rmse)
 
In [4]:
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
import xgboost as xgb
import lightgbm as lgb
 
In [5]:
model_gb = GradientBoostingRegressor(n_estimators=3000, learning_rate=0.05,
                                   max_depth=4, max_features='sqrt',
                                   min_samples_leaf=15, min_samples_split=10, 
                                   loss='huber')
 
In [6]:
model_xgb = xgb.XGBRegressor(colsample_bytree=0.4603, gamma=0.0468, 
                             learning_rate=0.05, max_depth=3, 
                             min_child_weight=1.7817, n_estimators=2200,
                             reg_alpha=0.4640, reg_lambda=0.8571,
                             subsample=0.5213, silent=1,
                             random_state =7, nthread = -1)
 
In [7]:
model_lgb = lgb.LGBMRegressor(objective='regression',num_leaves=5,
                              learning_rate=0.05, n_estimators=720,
                              max_bin = 55, bagging_fraction = 0.8,
                              bagging_freq = 5, feature_fraction = 0.2319,
                              feature_fraction_seed=9, bagging_seed=9,
                              min_data_in_leaf =6, min_sum_hessian_in_leaf = 11)
 
In [8]:
model_rf = RandomForestRegressor(n_estimators=3000, 
                                   max_depth=4, max_features='sqrt',
                                   min_samples_leaf=15, min_samples_split=10)
In [9]:
score = rmsle_cv(model_gb)
gb_score = score.mean()
print("GradientBoostingRegressor score: {:.4f} ({:.4f})".format(score.mean(), score.std()))
 
GradientBoostingRegressor score: 0.1161 (0.0065)
 
In [10]:
score = rmsle_cv(model_xgb)
xgb_score = score.mean()
print("XGBRegressor score: {:.4f} ({:.4f})".format(score.mean(), score.std()))
 
XGBRegressor score: 0.1145 (0.0057)
 
In [11]:
score = rmsle_cv(model_lgb)
lgb_score = score.mean()
print("LGBMRegressor score: {:.4f} ({:.4f})".format(score.mean(), score.std()))
 
LGBMRegressor score: 0.1163 (0.0046)
 
In [12]:
score = rmsle_cv(model_rf)
print("RandomForestRegressor score: {:.4f} ({:.4f})".format(score.mean(), score.std()))
 
RandomForestRegressor score: 0.1798 (0.0099)
 

GradientBoostingRegressor, XGBRegressor, LGBMRegressor 세가지는 Linear Regressor 보다 성능이 잘나왔지만,

Random forest 는 성능이 현저히 낮았다. 파라매터 튜닝을 안한 탓도 있겠지만 통상적으로 이렇게 나온다.

 

 

제일 잘나온 xgb로 제출을 해보니 0.12517 로 상위 22% 정도에 Rank 되었다 !

ElasticNet보다 8% 향상 된 수치이다.

또 다른 중요 차이점이 있다면 train set의 결과와 차이가 줄어들었다. 즉, 오버 피팅이 줄어든 샘이다.

오버 피팅에 강하다고 하는 xgb의 강점이 여기서도 빛을 발한다.

하지만 아직 조금 아쉽다.

등수를 조금 더 향상 시켜보도록 하자.

 

Ensemble of Ensemble Modeling

 

결과가 잘나온 앙상블 모델 3개를 앙상블 하면 결과가 더 잘나올 것이다. 진행해보자.

In [13]:
model_gb.fit(X_train, y_train)
model_xgb.fit(X_train, y_train)
model_lgb.fit(X_train, y_train)
 
In [14]:
pred_gb = model_gb.predict(X_test)
pred_xgb = model_xgb.predict(X_test)
pred_lgb = model_lgb.predict(X_test)
 
In [15]:
total_weight = (1. / gb_score) + (1. / xgb_score) + (1. / lgb_score)
pred = (pred_gb * (1. / gb_score) + pred_xgb * (1. / xgb_score) +  pred_lgb * (1. / lgb_score)) / total_weight
pd_test_pred = pd.DataFrame({'Id': Id_test, 'SalePrice': np.expm1(pred)})
pd_test_pred.to_csv('submission.csv', index=False)
 

총합이 1이 되게 모델마다 weight를 정해주었다.

캐글에서는 임의로 개발자의 직감에 의해서 정하는 경우가 많았던것 같은데

나는 train set 결과인 rmse의 역수에 비례해서 가중치를 주었다.

각 모델의 가중치와 예측값을 곱해서 최종 결과물 산출했다.

 

 

그 결과 0.12176을 기록해 상위 13% 까지 올랐다!

내심 10% 안에 들기를 바랬는데 무리였다보다.

다음번엔 잘나온 모델들은 합쳐서 ensemble이 아닌 stacking 기법을 사용해보자.

 

In [16]:
# 티스토리에 올리기 위한 레이아웃 조정
from IPython.core.display import display, HTML
display(HTML("<style>.container {width:100% !important;}</style>"))
 
 

다음글에는 10% 이내를 목표로 모델 stacking 을 진행해보자.

 

댓글