[파이썬 실습] 정규화 모델 실습(2)

k fold cross validation으로 하이퍼 파라미터 찾기

 

※ Train set / Test set

- Test set을 통해 모델의 성능을 검증하고, 하이퍼 파라미터를 설정하게 되면 구축된 모델이 test set에 overfitting 될 수 있다. 일반적으로 하이퍼 파라미터를 탐색하기 위해서 따로 에러 값을 찾는 검증용 데이터셋(validation set)을 사용하게 된다.

K-fold Cross Validation

※ Train set / Validation set / Test set > K-fold cross validation

  • 모든 데이터셋을 Train에 활용할 수 있다.
  • 정확도를 향상시킬 수 있다.
  • 데이터 부족으로 인한 underfitting을 방지할 수 있다.
  • 모든 데이터셋을 Validation에 활용할 수 있다.
  • 평가에 사용되는 데이터 편중을 막을 수 있다.
  • 평가 결과에 따라 좀 더 일반화된 모델을 구축할 수 있다.

 

cv = 5
max_iter = 5000

n_trials = 50
def myrange(start, end, step):
    r = start
    while(r < end):
        yield r
        r += step
        
alpha_list = list(reversed([round(i,2) for i in myrange(0.01, 10, 0.1)]))
model_Lasso = LassoCV(alphas = alpha_list, cv = cv, n_jobs = -1, random_state = 1, max_iter = max_iter)
model_Lasso.fit(X_train, y_train)
model_Lasso.alpha_

라쏘 모델에 적용을 하게 되면 최적의 알파 값 9.91을 도출하게 된다.

최적의 알파값으로 예측을 수행할 수 있다.

pred_train_LR = model_LR.predict(X_train)
pred_test_LR = model_LR.predict(X_test)
pred_train_Lasso = model_Lasso.predict(X_train)
pred_test_Lasso = model_Lasso.predict(X_test)
train_rmse_LR = np.sqrt(mean_squared_error(y_train, pred_train_LR))
train_mae_LR = mean_absolute_error(y_train, pred_train_LR)
train_r2_LR = r2_score(y_train, pred_train_LR)

test_rmse_LR = np.sqrt(mean_squared_error(y_test, pred_test_LR))
test_mae_LR = mean_absolute_error(y_test, pred_test_LR)
test_r2_LR = r2_score(y_test, pred_test_LR)

train_rmse_Lasso = np.sqrt(mean_squared_error(y_train, pred_train_Lasso))
train_mae_Lasso = mean_absolute_error(y_train, pred_train_Lasso)
train_r2_Lasso = r2_score(y_train, pred_train_Lasso)

test_rmse_Lasso = np.sqrt(mean_squared_error(y_test, pred_test_Lasso))
test_mae_Lasso = mean_absolute_error(y_test, pred_test_Lasso)
test_r2_Lasso = r2_score(y_test, pred_test_Lasso)
results = pd.DataFrame(index = ['rmse', 'mae', 'r2'], columns = ['LR train', 'LR test', 'Lasso train', 'Lasso test'])
results.loc['rmse', 'LR train'] = train_rmse_LR
results.loc['mae', 'LR train'] = train_mae_LR
results.loc['r2', 'LR train'] = train_r2_LR

results.loc['rmse', 'LR test'] = test_rmse_LR
results.loc['mae', 'LR test'] = test_mae_LR
results.loc['r2', 'LR test'] = test_r2_LR

results.loc['rmse', 'Lasso train'] = train_rmse_Lasso
results.loc['mae', 'Lasso train'] = train_mae_Lasso
results.loc['r2', 'Lasso train'] = train_r2_Lasso

results.loc['rmse', 'Lasso test'] = test_rmse_Lasso
results.loc['mae', 'Lasso test'] = test_mae_Lasso
results.loc['r2', 'Lasso test'] = test_r2_Lasso
results

최적의 알파값으로 도출된 라쏘의 테스트값이 LR값보다 훨씬 좋은 성능을 가지고 있는 것을 확인할 수 있다.

 

k fold cross validation으로 하이퍼 파라미터 찾기 + 모델 비교 선택

 

models = {}

n_trials = 20
alpha_list = 10 ** np.linspace(-3, 3, n_trials)

cv = 5

alpha_list = list(reversed([round(i, 2) for i in myrange(0.01, 10, 0.1)]))
l1_list = list(reversed([round(i, 2) for i in myrange(0, 1, 0.1)]))

max_iter = 5000
model = LassoCV(alphas = alpha_list, cv = cv, n_jobs = -1, random_state = 1, max_iter = max_iter)
model.fit(X_train, y_train)
models['Lasso'] = Lasso(alpha = model.alpha_, max_iter = max_iter)
model = RidgeCV(alphas = alpha_list, cv = cv)
model.fit(X_train, y_train)
models['Ridge'] = Ridge(alpha = model.alpha_)
model = ElasticNetCV(alphas = alpha_list, l1_ratio = l1_list,
                    cv = cv, random_state = 1, n_jobs = -1, max_iter = max_iter)
model.fit(X_train, y_train)
models['ElasticNet'] = ElasticNet(alpha = model.alpha_, l1_ratio = model.l1_ratio_, max_iter = max_iter)
for name in models.keys():
    print(models[name])
    print('-'*100)

최적의 하이퍼 파라미터 값이 도출되었다.

 

모델 비교 선택

kf = KFold(cv, shuffle = True, random_state = 1)
kf
score = {}
for name in  models.keys():
    # save score for each model
    if name not in score:
        score[name] = []
        
    # 모델
    reg = models[name]
    for i_train, i_valid in kf.split(X_train):
        # 학습
        reg.fit(X_train[i_train], y_train[i_train])
        # 예측
        y_pred = reg.predict(X_train[i_valid])
        RMSE = np.sqrt(mean_squared_error(y_train[i_valid], y_pred))
        score[name].append(RMSE)
score

score 값을 보면 5개의 폴드를 사용했기 때문에 5개의 rmse가 도출이 되는 것을 확인할 수 있다.

results = pd.DataFrame(score)
results

ax = results.plot.bar()
pd.concat([results.mean(), results.std()], axis = 1, keys = ['mean', 'std'])

최종적인 예측은 평균값, 표준편차를 사용하게 된다.

ElasticNet이 가장 좋은 성능을 보이는 것을 확인할 수 있다.

 

가장 성능이 좋았던 ElasticNet을 기준으로 성능을 확인해볼 수 있다.

model = models['ElasticNet'].fit(X_train, y_train)
pred_train = model.predict(X_train)
pred_test = model.predict(X_test)
rmse_train = np.sqrt(mean_squared_error(y_train, pred_train))
rmse_test = np.sqrt(mean_squared_error(y_test, pred_test))
print(f'train rmse : {rmse_train:.4f}')
print(f'test rmse : {rmse_test:.4f}')

r2_train = r2_score(y_train, pred_train)
r2_test = r2_score(y_test, pred_test)
print(f'train r2 : {r2_train:.4f}')
print(f'test r2 : {r2_test:.4f}')

약 88%의 성능값을 확인할 수 있다.

 

예측결과 plotting

plt.figure(figsize = (8, 8))
plt.title('실제값 vs 모델 출력값', fontsize = 16)
plt.scatter(y_train, pred_train, c = 'red', alpha = 0.5)
plt.scatter(y_test, pred_test, c = 'blue', alpha = 0.5)
plt.plot(y_test, y_test, c = 'gray')
plt.plot(y_train, y_train, c = 'gray')
plt.xlabel('실제값', size = 10)
plt.ylabel('모델 출력 값', size = 10)
plt.show()

X축은 실제값, Y값은 출력 값이기 때문에 일직선을 따라가야 가장 정확한 예측을 했다고 볼 수 있다. 위 그래프를 보면 예측을 잘했다고 확인할 수 있다.

 

계수값을 변수 중요도로 생각하기

model = models['ElasticNet'].fit(X_train, y_train)

coef_df = pd.DataFrame(model.coef_.reshape(-1, 1), index = X_test_final.columns, columns = ['coefficients'])
coef_df.to_csv('coef.csv')
coef_df

 

각 변수에 대한 베타값들이 산출된 것을 확인할 수 있다.

이를 중요도로 생각하기 위해 절댓값을 취할 것이다.

절댓값을 취하는 이유는 음의 방향이든 양의 방향이든 영향을 미치는 정도를 파악할 것이기 때문이다.

coefficents = np.abs(coef_df.coefficients)
index = np.argsort(coefficents)[::-1]
print(index)
importance = coefficents[index]
columns = [list(coef_df.index)[i] for i in index]
importance = importance[importance > 0]
num_print = 20

plt.figure(figsize = (10, 3))
plt.title('Feature Importances= ABS(coefficients)')
plt.bar(range(num_print),
       importance[:num_print],
       align = 'center')
plt.xticks(range(num_print), columns[:num_print], rotation = 90, fontsize = 11)
plt.show()

상위 20개의 기여도가 큰 정도를 파악해보았다. OverallQual=9가 가장 중요도가 큰 변수라고 확인할 수 있다.

 

TAGS.

Comments