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

kaggle 주택 가격 예측(5) - Stacking과 Blending으로 등수 올리기(상위 6%)

by 썽하 2020. 8. 24.

저번 글에는 몇몇 ensemble 모델을 조합해서 상위 13%에 랭크해보았다.

이번 글에서는 모델 stacking과 blending을 이용하여 상위 10% 이내에 랭크해보자.

 

상위 6% 결과 미리보기


 

 

 

 

 

 

 

 

 

 

prediction with stacking models

 

임포팅, 데이터 로딩

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.metrics import mean_squared_error, make_scorer
from sklearn.pipeline import make_pipeline
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,)
 

모델 준비

 

지난번에 잘 나왔던 모델들을 준비하자. 추가적으로 Support vector regressor도 준비해보았다.(캐글 노트북을 살펴보니 잘 나온다고,.) ElasticNet 은 Lasso와 동일한 성능을 나타냈으므로 제외시킨다.

  • GradientBoostingRegressor
  • XGBRegressor
  • LGBMRegressor
  • Support vector regressor
  • Lasso
  • Ridge
In [3]:
#Validation function
n_folds = 12

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
from sklearn.linear_model import LinearRegression, LassoCV, RidgeCV, ElasticNetCV
from sklearn.kernel_ridge import KernelRidge
from sklearn.svm import SVR
 
In [5]:
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]:
xgboost = 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]:
lightgb = 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,n_jobs=-1)
 
In [8]:
svr = make_pipeline(RobustScaler(), SVR(C= 20, epsilon= 0.008, gamma=0.0003))
 

캐글 노트북에선 잘 나오더니 내 PC에선 잘 안 나온다. 그래도 한번 사용해보자.

In [9]:
alpha = 0.0033000000000000004
lasso = LassoCV(alphas = [alpha * .6, alpha * .65, alpha * .7, alpha * .75, alpha * .8, 
                          alpha * .85, alpha * .9, alpha * .95, alpha, alpha * 1.05, 
                          alpha * 1.1, alpha * 1.15, alpha * 1.25, alpha * 1.3, alpha * 1.35, 
                          alpha * 1.4], 
                max_iter = 50000, cv = 10, n_jobs=-1)
lasso = make_pipeline(RobustScaler(),lasso)
 
In [10]:
alpha = 0.6
ridge = RidgeCV(alphas = [alpha * .6, alpha * .65, alpha * .7, alpha * .75, alpha * .8, alpha * .85, 
                          alpha * .9, alpha * .95, alpha, alpha * 1.05, alpha * 1.1, alpha * 1.15,
                          alpha * 1.25, alpha * 1.3, alpha * 1.35, alpha * 1.4], cv = 10)
ridge = make_pipeline(RobustScaler(),ridge)
 

Score 확인

In [11]:
score = rmsle_cv(gb)
gb_score = score.mean()
print("GradientBoostingRegressor score: {:.4f} ({:.4f})".format(score.mean(), score.std()))
 
GradientBoostingRegressor score: 0.1129 (0.0161)
 
In [12]:
score = rmsle_cv(xgboost)
xgb_score = score.mean()
print("XGBRegressor score: {:.4f} ({:.4f})".format(score.mean(), score.std()))
 
XGBRegressor score: 0.1145 (0.0145)
 
In [13]:
score = rmsle_cv(lightgb)
lgb_score = score.mean()
print("LGBMRegressor score: {:.4f} ({:.4f})".format(score.mean(), score.std()))
 
LGBMRegressor score: 0.1148 (0.0147)
 
In [14]:
score = rmsle_cv(svr)
print("svr score: {:.4f} ({:.4f})".format(score.mean(), score.std()))
 
svr score: 0.1723 (0.0158)
 
In [15]:
score = rmsle_cv(lasso)
print("lasso score: {:.4f} ({:.4f})".format(score.mean(), score.std()))
 
lasso score: 0.1152 (0.0137)
 
In [16]:
score = rmsle_cv(ridge)
print("ridge score: {:.4f} ({:.4f})".format(score.mean(), score.std()))
 
ridge score: 0.1146 (0.0163)
 

SVR을 제외하고는 고만고만한 결과가 나왔다.

 

Stacking Model

 

위 5개 알고리즘을 조합한 Stacking Model을 만들어보자. (svr은 제거)

In [17]:
from mlxtend.regressor import StackingCVRegressor
 
In [18]:
# 6개 모델 위에 xgboost 모델을 하나 더올려 stacking을 한다.
stack = StackingCVRegressor(regressors=(gb, xgboost, lightgb, lasso, ridge),#svr
                                meta_regressor=xgboost,
                                use_features_in_secondary=True,
                                n_jobs=-1)
 
In [19]:
score = rmsle_cv(stack)
print("stack score: {:.4f} ({:.4f})".format(score.mean(), score.std()))
 
stack score: 0.1115 (0.0158)
 

드디어 0.11xxx 초반에 진입을 했다. train set에서는 스태킹이 기존 알고리즘보다는 더 좋은 성능을 보여준다. 오버 피팅인지 아닌지는 더 살펴봐야겠지만..

In [20]:
stack_model = stack.fit(np.array(X_train), y_train)
 
In [21]:
pred = stack_model.predict(np.array(X_test))
pd_test_pred = pd.DataFrame({'Id': Id_test, 'SalePrice': np.expm1(pred)})
pd_test_pred.to_csv('submission.csv', index=False)
 

맙소사 오히려 ensemble 모델 몇 개를 같이 사용한 것보다 더 낮게 나왔다.
(캐글 노트북을 읽어보면서 알게 되었는데 이러한 방법을 blending이라고 한다고 한다)
stacking 모델을 다른 모델들과 blending 해보도록 하자.

In [22]:
gb_model = gb.fit(X_train, y_train)
xgboost_model = xgboost.fit(X_train, y_train)
lightgb_model = lightgb.fit(X_train, y_train)
svr_model = svr.fit(X_train, y_train)
lasso_model = lasso.fit(X_train, y_train)
ridge_model = ridge.fit(X_train, y_train)
 
In [23]:
# 블랜딩은 오버피팅에 조금더 견고한 결과물을 만들어 낸다고 한다.
def blended_predictions(X):
    return ((0.05 * lasso_model.predict(X)) + \
            (0.05 * ridge_model.predict(X)) + \
            (0.05 * svr_model.predict(X)) + \
            (0.1 * gb_model.predict(X)) + \
            (0.15 * xgboost_model.predict(X)) + \
            (0.1 * lightgb_model.predict(X)) + \
            (0.5 * stack_model.predict(np.array(X))))
 
In [24]:
pred = blended_predictions(X_test)
pd_test_pred = pd.DataFrame({'Id': Id_test, 'SalePrice': np.expm1(pred)})
pd_test_pred.to_csv('submission.csv', index=False)
 

상위 6%에 랭크되었다. 이 정도면 만족스러운 결과다.

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

 

처음에는 10% 이내 진입이라 만족스러웠지만, 5%보다 큰 6%이라는 숫자는 살짝 불만족스럽다.

하지만 여기에서 그만 하려고 한다.

랭킹 보드를 살펴보니 100위권 안쪽의 사람들이 하나같이 말도 안 되게 낮고, 동일 한 점수를 기록하고 있는데,

추측건대 솔루션 공유 + 수작업 노가다의 결과물인 것 같다.

그렇게까지 랭킹을 올리고 싶지 않으니. 이번 프로젝트는 여기서 그만하고, 다음 프로젝트를 준비하자.

댓글