작성
·
418
0
auc score 에 초점을 맞춰서인지 f1 score를 측정해보니,
거의 0에 가까운 값이 되었습니다. ㅠ
실제로는 못쓰는 모델이겠죠?
캐글에 제출해보려 했는데 캐글이 제공해주는 test data에 대해서 4개 빼고 전부 0이라 예측하더라구요 ㅜ
답변 7
0
0
이 데이터 세트는 특성이 고객 불만족이 데이터가 극히 일부분인 imbalanced 데이터세트라 고객 불만족 데이터를 잘 맞추지 못할 경우 recall이 굉장히 저조해 지는 군요. recall이 저조해서 f1 score가 잘 나오지 않습니다.
이 경우는 hyper parameter tuning을 recall 또는 f1 score에 맞춰야 할 것 같습니다. bayesian optimization도 f1 score로 변경해야 될 것 같습니다.
0
0
### 데이터 전처리
!pip install bayesian-optimization
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
cust_df = pd.read_csv(r"C:\Users\user\Desktop\datasets\santander-customer-satisfaction/train.csv",encoding='latin-1')
print('dataset shape:', cust_df.shape)
cust_df.head(3)
cust_df.info()
print(cust_df['TARGET'].value_counts())
unsatisfied_cnt = cust_df[cust_df['TARGET'] == 1]['TARGET'].count()
total_cnt = cust_df['TARGET'].count()
print('unsatisfied 비율은 {0:.2f}'.format((unsatisfied_cnt / total_cnt)))
cust_df.describe( )
print(cust_df['var3'].value_counts( )[:10])
# var3 피처 값 대체 및 ID 피처 드롭
cust_df['var3'].replace(-999999, 2, inplace=True)
cust_df.drop('ID',axis=1 , inplace=True)
# 피처 세트와 레이블 세트분리. 레이블 컬럼은 DataFrame의 맨 마지막에 위치해 컬럼 위치 -1로 분리
X_features = cust_df.iloc[:, :-1]
y_labels = cust_df.iloc[:, -1]
print('피처 데이터 shape:{0}'.format(X_features.shape))
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X_features, y_labels,
test_size=0.2, random_state=0)
train_cnt = y_train.count()
test_cnt = y_test.count()
print('학습 세트 Shape:{0}, 테스트 세트 Shape:{1}'.format(X_train.shape , X_test.shape))
print(' 학습 세트 레이블 값 분포 비율')
print(y_train.value_counts()/train_cnt)
print('\n 테스트 세트 레이블 값 분포 비율')
print(y_test.value_counts()/test_cnt)
from xgboost import XGBClassifier
from sklearn.metrics import roc_auc_score
# n_estimators는 500으로, random state는 예제 수행 시마다 동일 예측 결과를 위해 설정.
xgb_clf = XGBClassifier(n_estimators=500, random_state=156)
# 성능 평가 지표를 auc로, 조기 중단 파라미터는 100으로 설정하고 학습 수행.
xgb_clf.fit(X_train, y_train, early_stopping_rounds=100,
eval_metric="auc", eval_set=[(X_train, y_train), (X_test, y_test)])
xgb_roc_score = roc_auc_score(y_test, xgb_clf.predict_proba(X_test)[:,1],average='macro')
print('ROC AUC: {0:.4f}'.format(xgb_roc_score))
from sklearn.model_selection import GridSearchCV
# 하이퍼 파라미터 테스트의 수행 속도를 향상시키기 위해 n_estimators를 100으로 감소
xgb_clf = XGBClassifier(n_estimators=100)
params = {'max_depth':[5, 7] , 'min_child_weight':[1,3] ,'colsample_bytree':[0.5, 0.75] }
# 하이퍼 파라미터 테스트의 수행속도를 향상 시키기 위해 cv 를 지정하지 않음.
gridcv = GridSearchCV(xgb_clf, param_grid=params)
gridcv.fit(X_train, y_train, early_stopping_rounds=30, eval_metric="auc",
eval_set=[(X_train, y_train), (X_test, y_test)])
print('GridSearchCV 최적 파라미터:',gridcv.best_params_)
xgb_roc_score = roc_auc_score(y_test, gridcv.predict_proba(X_test)[:,1], average='macro')
print('ROC AUC: {0:.4f}'.format(xgb_roc_score))
# n_estimators는 1000으로 증가시키고, learning_rate=0.02로 감소, reg_alpha=0.03으로 추가함.
xgb_clf = XGBClassifier(n_estimators=1000, random_state=156, learning_rate=0.02, max_depth=5,\
min_child_weight=1, colsample_bytree=0.75, reg_alpha=0.03)
# evaluation metric을 auc로, early stopping은 200 으로 설정하고 학습 수행.
xgb_clf.fit(X_train, y_train, early_stopping_rounds=200,
eval_metric="auc",eval_set=[(X_train, y_train), (X_test, y_test)])
xgb_roc_score = roc_auc_score(y_test, xgb_clf.predict_proba(X_test)[:,1],average='macro')
print('ROC AUC: {0:.4f}'.format(xgb_roc_score))
# n_estimators는 1000으로 증가시키고, learning_rate=0.02로 감소, reg_alpha=0.03으로 추가함.
xgb_clf = XGBClassifier(n_estimators=1000, random_state=156, learning_rate=0.02, max_depth=7,\
min_child_weight=1, colsample_bytree=0.75, reg_alpha=0.03)
# evaluation metric을 auc로, early stopping은 200 으로 설정하고 학습 수행.
xgb_clf.fit(X_train, y_train, early_stopping_rounds=200,
eval_metric="auc",eval_set=[(X_train, y_train), (X_test, y_test)])
xgb_roc_score = roc_auc_score(y_test, xgb_clf.predict_proba(X_test)[:,1],average='macro')
print('ROC AUC: {0:.4f}'.format(xgb_roc_score))
from xgboost import plot_importance
import matplotlib.pyplot as plt
%matplotlib inline
fig, ax = plt.subplots(1,1,figsize=(10,8))
plot_importance(xgb_clf, ax=ax , max_num_features=20,height=0.4)
### LightGBM 모델 학습과 하이퍼 파라미터 튜닝
from lightgbm import LGBMClassifier
lgbm_clf = LGBMClassifier(n_estimators=500)
evals = [(X_test, y_test)]
lgbm_clf.fit(X_train, y_train, early_stopping_rounds=100, eval_metric="auc", eval_set=evals,
verbose=True)
lgbm_roc_score = roc_auc_score(y_test, lgbm_clf.predict_proba(X_test)[:,1],average='macro')
print('ROC AUC: {0:.4f}'.format(lgbm_roc_score))
from sklearn.metrics import f1_score
f1_score(y_test, lgbm_clf.predict(X_test))
from sklearn.model_selection import GridSearchCV
# 하이퍼 파라미터 테스트의 수행 속도를 향상시키기 위해 n_estimators를 100으로 감소
LGBM_clf = LGBMClassifier(n_estimators=200)
params = {'num_leaves': [32, 64 ],
'max_depth':[128, 160],
'min_child_samples':[60, 100],
'subsample':[0.8, 1]}
# 하이퍼 파라미터 테스트의 수행속도를 향상 시키기 위해 cv 를 지정하지 않습니다.
gridcv = GridSearchCV(lgbm_clf, param_grid=params)
gridcv.fit(X_train, y_train, early_stopping_rounds=30, eval_metric="auc",
eval_set=[(X_train, y_train), (X_test, y_test)])
print('GridSearchCV 최적 파라미터:', gridcv.best_params_)
lgbm_roc_score = roc_auc_score(y_test, gridcv.predict_proba(X_test)[:,1], average='macro')
print('ROC AUC: {0:.4f}'.format(lgbm_roc_score))
lgbm_clf = LGBMClassifier(n_estimators=1000, num_leaves=32, sumbsample=0.8, min_child_samples=100,
max_depth=128)
evals = [(X_test, y_test)]
lgbm_clf.fit(X_train, y_train, early_stopping_rounds=100, eval_metric="auc", eval_set=evals,
verbose=True)
lgbm_roc_score = roc_auc_score(y_test, lgbm_clf.predict_proba(X_test)[:,1],average='macro')
print('ROC AUC: {0:.4f}'.format(lgbm_roc_score))
### BaysianOptimization을 이용한 하이퍼 파라미터 튜닝
하이퍼 파라미터 튜닝 대상을 Dictionary 형태로 정의합니다. 이때 개별 하이퍼 파라미터는 튜플형태의 범위값으로 주어집니다.
예를 들어 num_leaves의 값을 24~45 사이의 값을 입력하려면 'num_leaves':(24, 45)로 부여해야 합니다.
이 때 유의해야 할 사항은 num_leaves는 정수형값만 가능한 하이퍼 파라미터임에도 불구하고 BaysianOptimization 클래스가 해당 파라미터의 범위값을 입력 받으면 이를 무조건 정수형이 아닌 실수형 값으로
인식하여 값을 추출하는 것입니다. 즉 24.5, 25.4, 30.2, 27.2 와 같이 실수형 값을 num_leaves 값으로 설정하려고 시도하는데, 이는 실행 오류를 발생 시킵니다.
이러한 실행 오류를 막기 위해서는 호출되는 BayesianOptimization 평가 함수내에서 XGBoost/LightGBM의 하이퍼 파라미터를 다시 정수형 값으로 변경하면 됩니다. 이에 대해서는 다시 뒤에서 언급하도록 하겠습니다.
bayes_params = {
'num_leaves': (24, 45),
'colsample_bytree':(0.5, 1),
'subsample': (0.5, 1),
'max_depth': (4, 12),
'reg_alpha': (0, 0.5),
'reg_lambda': (0, 0.5),
'min_split_gain': (0.001, 0.1),
'min_child_weight':(5, 50)
}
테스트 해볼 하이퍼 파라미터의 범위 값을 설정하였으면 BaysianOptimization에서 호출하여 모델을 최적화하는 함수를 만들어 보겠습니다.
해당 함수는 BaysianOptimization에서 하이퍼 파라미터를 튜닝하기 위해 호출되면 제대로 튜닝이 되고 있는지를 판단하기 위해서 모델을 학습/평가하고 이에 따른 평가 지표를 반환하는 형식으로 만들어집니다. 이 평가 함수는 BayesianOptimization 객체에서 파라미터를 변경하면서 호출되므로 함수의 인자로 앞에서 딕셔너리로 설정된 파라미터들을 가지게 됩니다.
from lightgbm import LGBMClassifier
from sklearn.metrics import roc_auc_score
def lgb_roc_eval(num_leaves, colsample_bytree, subsample, max_depth, reg_alpha, reg_lambda, min_split_gain, min_child_weight):
params = {
"n_estimator":200,
"learning_rate":0.02,
'num_leaves': int(round(num_leaves)),
'colsample_bytree': colsample_bytree,
'subsample': subsample,
'max_depth': int(round(max_depth)),
'reg_alpha': reg_alpha,
'reg_lambda': reg_lambda,
'min_split_gain': min_split_gain,
'min_child_weight': min_child_weight,
'verbosity': -1
}
print("params:", params)
lgb_model = LGBMClassifier(**params)
lgb_model.fit(X_train, y_train, eval_set=[(X_test, y_test)], early_stopping_rounds=30, eval_metric="auc", verbose=False )
best_iter = lgb_model.best_iteration_
print('best_iter:', best_iter)
valid_proba = lgb_model.predict_proba(X_test, num_iteration=best_iter)[:, 1]
roc_preds = roc_auc_score(y_test, valid_proba)
print('roc_auc:', roc_preds)
return roc_preds
BayesianOptimization 객체를 생성합니다.
이때 생성 인자로 앞에서 만든 평가함수 lgb_roc_eval 함수와 튜닝할 하이퍼 파라미터의 범위값을 설정한 딕셔너리 변수인 bayes_params를 입력합니다.
from bayes_opt import BayesianOptimization
BO_lgb = BayesianOptimization(lgb_roc_eval, bayes_params, random_state=0)
이제 입력받은 평가함수에 튜닝할 하이퍼 파라미터의 값을 반복적으로 입력하여 최적 하이퍼 파라미터를 튜닝할 준비가 되었습니다.
BayesianOptimization객체에서 maximize()메소드를 호출하면 이를 수행할 수 있습니다.
BO_lgb.maximize(init_points=5, n_iter=10)
BayesianOptimization 객체의 res 속성은 하이퍼 파라미터 튜닝을 하는 과정에서의 metric 값과 그때의 하이퍼 파라미터 값을 가지고 있음.
BO_lgb.res
BayesianOptimization 객체의 max 속성은 최고 높은 성능 Metric를 가질때의 하이퍼 파라미터 값을 가지고 있음.
BO_lgb.max
max_params = BO_lgb.max['params']
max_params['num_leaves'] = int(round(max_params['num_leaves']))
max_params['max_depth'] = int(round(max_params['max_depth']))
lgbm_clf = LGBMClassifier(n_estimators=1000, learning_rate=0.02, **max_params)
evals = [(X_test, y_test)]
lgbm_clf.fit(X_train, y_train, early_stopping_rounds=100, eval_metric="auc", eval_set=evals,
verbose=True)
lgbm_roc_score = roc_auc_score(y_test, lgbm_clf.predict_proba(X_test)[:,1],average='macro')
print('ROC AUC: {0:.4f}'.format(lgbm_roc_score))
p = lgbm_clf.predict(X_test)
from sklearn.metrics import f1_score
f1_score(y_test, p)
test_df = pd.read_csv(r'C:\Users\user\Desktop\datasets\santander-customer-satisfaction\test.csv',
encoding = 'latin-1')
test_df['var3'].replace(-999999, 2, inplace=True)
test_df.drop('ID',axis=1 , inplace=True)
testp = lgbm_clf.predict(test_df)
testp_df = pd.Series(testp)
testp_df.value_counts()
0
0
하지만 강사님이 깃허브에 올려주신 bayesian opt 코드를 그대로 돌려도 f1_score 가 매우 낮게 나오네요 ㅜ
roc_auc_score 가 높으면 f1_score 가 높아야하는게 일반적인 것으로 알고 있는데, 다른 데이터에 이것저것 적용헤볼 경우에도 이런 사례가 간혹 있었네요 ㅜㅜ
어떤 문제인지 파악이 어려워 질문드립니다.
0