[Applied Predictive Modeling] Feature Importances

Prepare Data

  • Import H1N1 Data
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split

# 타겟생성
target = 'vacc_seas_f'
# 학습데이터 features, labels 를 병합
train = pd.merge(pd.read_csv('https://ds-lecture-data.s3.ap-northeast-2.amazonaws.com/vacc_flu/train.csv'), 
                 pd.read_csv('https://ds-lecture-data.s3.ap-northeast-2.amazonaws.com/vacc_flu/train_labels.csv')[target], left_index=True, right_index=True)
test = pd.read_csv('https://ds-lecture-data.s3.ap-northeast-2.amazonaws.com/vacc_flu/test.csv')



# 80/20 비율 학습/테스트 데이터 분리
train, val = train_test_split(train, train_size=0.80, test_size=0.20, 
                              stratify=train[target], random_state=2)

def engineer(df):
    """특성을 엔지니어링 하는 함수입니다."""
    
    # 새로운 특성 생성
    behaviorals = [col for col in df.columns if 'behavioral' in col] 
    df['behaviorals'] = df[behaviorals].sum(axis=1)
    
    dels = [col for col in df.columns if ('employment' in col or 'h1n1' in col)]
    df.drop(columns=dels, inplace=True)
        
    return df

train = engineer(train)
val = engineer(val)
test = engineer(test)


X_train = train.drop(columns=target)
y_train = train[target]
X_val = val.drop(columns=target)
y_val = val[target]
X_test = test


from category_encoders import OrdinalEncoder
from sklearn.impute import SimpleImputer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline

pipe = make_pipeline(
    OrdinalEncoder(),
    SimpleImputer(), 
    RandomForestClassifier(n_estimators=100, random_state=2, n_jobs=-1)
)


pipe
'''
Pipeline(steps=[('ordinalencoder', OrdinalEncoder()),
                ('simpleimputer', SimpleImputer()),
                ('randomforestclassifier',
                 RandomForestClassifier(n_jobs=-1, random_state=2))])
'''


from sklearn.metrics import classification_report
# train 학습, 검증셋 정확도
pipe.fit(X_train, y_train)
print('검증 정확도', pipe.score(X_val, y_val))

print(classification_report(y_val, pipe.predict(X_val)))
'''
검증 정확도 0.7526983750444787
              precision    recall  f1-score   support

           0       0.76      0.80      0.78      4608
           1       0.74      0.70      0.72      3823

    accuracy                           0.75      8431
   macro avg       0.75      0.75      0.75      8431
weighted avg       0.75      0.75      0.75      8431

'''

Permutation Importances(순열 중요도)

  • 모델 해석과 Feature selection을 위해 Permutation Importances(순열중요도)를 계산한다.
  • 기본 Feature importance는 빠르지만 특성 종류에 따라 부정확한 결과가 나올 수 있어 주의가 필요하다.
  • Permutation importance를 사용하면 더욱 정확한 계산이 가능하다.

특성 중요도 계산 방법 3가지

Feature Importances(Mean decrease impurity, MDI)

  • sklearn tree 기반 분류기에서 default로 사용되는 Feature importance는 속도는 빠르지만 결과를 주의해야 한다.
  • 각 특성을 모든 트리에 대해 평균불순도감소(Mean Decrease Impurity)를 계산한 값이다.
    • 상위노드에서 하위노드의 가중평균 불순도 차를 계산한 것이다.
  • 불순도감소(Impurity Decrease)
    • $\displaystyle \frac{N_t}{N}$ * (impurity - $\displaystyle\frac{N_{tR}}{N_t}$ * right_impurity - $\displaystyle\frac{N_{tL}}{N_t}$ * left_impurity)
    • $N$: 전체 관측치 수, $N_t$: 현재 노드 t에 존재하는 관측치 수
    • $N_{tL}$, $N_{tR}$: 노드 t 왼쪽(L)/오른쪽(R) 자식노드에 존재하는 관측치 수
    • 만약 sample_weight가 주어진다면, $N$, $N_t$, $N_{tR}$, $N_{tL}$는 가중합
    • Warning : impurity-based feature importances can be misleading for High cardinality features (many unique values).
    • 높은 Cadinality에 대해 Group이 편향되어 과적합을 일으키고 불순도가 높게 나오는 오류가 나서 잘못된 해석을 하기 쉽다.
1
2
3
4
5
6
7
8
9
10
11
# 특성 중요도
rf = pipe.named_steps['randomforestclassifier']
importances = pd.Series(rf.feature_importances_, X_train.columns)

%matplotlib inline
import matplotlib.pyplot as plt

n = 20
plt.figure(figsize=(10,n/2))
plt.title(f'Top {n} features')
importances.sort_values()[-n:].plot.barh();

스크린샷 2021-08-26 10 30 10

  • 다른 특성에 비해 비교적 High cardinality인 51개의 Category로 구성 된 state는 유의해서 봐야한다.
  • Tree 구성 중 분기에 이용될 확률이 높아 과적합 위험이 있다.
1
2
3
4
len(X_train['state'].value_counts())
'''
51
'''

Drop-Column Importance

  • 이론적으로 가장 좋아 보이지만, 매 특성을 drop한 후 fit을 다시 해야하기 때문에 느리다는 단점이 있다.
  • 특성이 n개 존재할 때 n + 1번 학습이 필요하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
column  = 'opinion_seas_risk'

# opinion_h1n1_risk 없이 fit
pipe = make_pipeline(
    OrdinalEncoder(), 
    SimpleImputer(), 
    RandomForestClassifier(n_estimators=100, random_state=2, n_jobs=-1)
)
pipe.fit(X_train.drop(columns=column), y_train)
score_without = pipe.score(X_val.drop(columns=column), y_val)
print(f'검증 정확도 ({column} 제외): {score_without}')

# opinion_h1n1_risk 포함 후 다시 학습
pipe = make_pipeline(
    OrdinalEncoder(), 
    SimpleImputer(), 
    RandomForestClassifier(n_estimators=100, random_state=2, n_jobs=-1)
)
pipe.fit(X_train, y_train)
score_with = pipe.score(X_val, y_val)
print(f'검증 정확도 ({column} 포함): {score_with}')

# opinion_h1n1_risk 포함 전 후 정확도 차이 계산
print(f'{column}의 Drop-Column 중요도: {score_with - score_without}')
'''
검증 정확도 (opinion_seas_risk 제외): 0.733127742853754
검증 정확도 (opinion_seas_risk 포함): 0.7526983750444787
opinion_seas_risk의 Drop-Column 중요도: 0.019570632190724635
'''

순열중요도(Permutation Importance, Mean Decrease Accuracy, MDA)

  • Permutation Importance는 기본 Feature Importance와 Drop-column Importance의 중간에 위치하는 특징이 있다.
  • Importance 측정은 관심있는 특성에만 무작위로 Noise를 주고 예측했을 때 Confusion Matrix(Acc, F1, $R^2$ 등)가 얼마나 감소하는지 측정한다.
  • Drop-column importance를 계산하기 위해 Retraining을 해야했다면, Permutation improtance는 Val data에서 각 특성을 제거하지 않고 특성값에 무작위로 Noise를 주어 기존 정보를 제거하여 특성이 기존에 하던 역할을 하지 못하게 하고 성능을 측정한다.
  • 이때 Noise를 주는 간단한 방법이 그 특성값들을 Sample 내에서 Shuffle or Permutation 하는 것이다.
  • 주로 쓰게 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# eli5 라이브러리 사용 순열 중요도 계산
from sklearn.pipeline import Pipeline
# encoder, imputer를 preprocessing으로 묶고 eli5 permutation 계산에 사용
pipe = Pipeline([
    ('preprocessing', make_pipeline(OrdinalEncoder(), SimpleImputer())),
    ('rf', RandomForestClassifier(n_estimators=100, random_state=2, n_jobs=-1)) 
])


# pipeline 생성 확인
pipe.named_steps
'''
{'preprocessing': Pipeline(steps=[('ordinalencoder', OrdinalEncoder()),
                 ('simpleimputer', SimpleImputer())]),
 'rf': RandomForestClassifier(n_jobs=-1, random_state=2)}
'''


pipe.fit(X_train, y_train)
print('검증 정확도: ', pipe.score(X_val, y_val))
'''
검증 정확도:  0.7526983750444787
'''


import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)

import eli5
from eli5.sklearn import PermutationImportance

# permuter 정의
permuter = PermutationImportance(
    pipe.named_steps['rf'], # model
    scoring='accuracy', # metric
    n_iter=5, # 다른 random seed를 사용하여 5번 반복
    random_state=2
)

# permuter 계산은 preprocessing 된 X_val 사용
X_val_transformed = pipe.named_steps['preprocessing'].transform(X_val)

# 실제로 fit 의미보다 스코어 다시 계산하는 작업
permuter.fit(X_val_transformed, y_val);


feature_names = X_val.columns.tolist()
pd.Series(permuter.feature_importances_, feature_names).sort_values()
'''
n_adult_r                     -0.003511
hhs_region                    -0.003108
census_region                 -0.003084
behavioral_face_mask          -0.003060
sex_i                         -0.002942
state                         -0.002918
behavioral_wash_hands         -0.002657
n_people_r                    -0.002562
behavioral_large_gatherings   -0.002538
behavioral_antiviral_meds     -0.002420
behavioral_avoidance          -0.002159
behavioral_outside_home       -0.002064
behavioral_touch_face         -0.001755
chronic_med_condition         -0.001613
census_msa                    -0.001542
behaviorals                   -0.001471
child_under_6_months          -0.001400
marital                       -0.001328
rent_own_r                    -0.000712
inc_pov                       -0.000474
raceeth4_i                    -0.000213
household_children            -0.000119
education_comp                 0.001234
health_insurance               0.002775
health_worker                  0.003060
opinion_seas_sick_from_vacc    0.004792
agegrp                         0.007733
opinion_seas_risk              0.041039
opinion_seas_vacc_effective    0.043814
doctor_recc_seasonal           0.071427
dtype: float64
'''


# 특성별 score 확인
eli5.show_weights(
    permuter, 
    top=None, # top n 지정 가능, None 일 경우 모든 특성 
    feature_names=feature_names # list 형식으로 넣어야 합니다
)

스크린샷 2021-08-26 10 46 57

Feature Selection

  • Improtance를 이용하여 Feature selection 한다.
  • Importance가 음수인 특성은 제외해도 성능에 영향이 없으며 모델학습 속도가 개선된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
print('특성 삭제 전:', X_train.shape, X_val.shape)
'''
특성 삭제 전: (33723, 30) (8431, 30)
'''


minimum_importance = 0.001
mask = permuter.feature_importances_ > minimum_importance
features = X_train.columns[mask]
X_train_selected = X_train[features]
X_val_selected = X_val[features]
print('특성 삭제 후:', X_train_selected.shape, X_val_selected.shape)
'''
특성 삭제 후: (33723, 8) (8431, 8)
'''


# pipeline 다시 정의
pipe = Pipeline([
    ('preprocessing', make_pipeline(OrdinalEncoder(), SimpleImputer())),
    ('rf', RandomForestClassifier(n_estimators=100, random_state=2, n_jobs=-1)) 
], verbose=1)

pipe.fit(X_train_selected, y_train);
'''
[Pipeline] ..... (step 1 of 2) Processing preprocessing, total=   0.1s
[Pipeline] ................ (step 2 of 2) Processing rf, total=   0.4s
'''


print('검증 정확도: ', pipe.score(X_val_selected, y_val))
'''
검증 정확도:  0.7513936662317637
'''


# 순열 중요도의 평균 감소값과 그 표준편차의 차가 양수인 특징 확인
permuter.feature_importances_ - permuter.feature_importances_std_ > 0
'''
array([False, False, False, False, False, False, False,  True, False,
       False,  True,  True,  True,  True,  True,  True, False, False,
       False, False, False, False, False, False, False, False, False,
       False, False, False])
'''

Boosting(xgboost for gradient boosting)

  • Classifier 문제에서 Tree Ensemble Model을 많이 사용한다.
  • Tree Ensemble Modeld은 RandomForest나 Gradiant Boosting Model을 이야기 하며 여러 문제에서 좋은 성능을 보인다.
  • Tree Model은 non-linear, non-monotonic 관계, 특성간 상호작용이 존재하는 데이터 학습에 적용하기 좋다.
  • 한 Tree를 깊게 학습시키면 과적합을 일으키기 쉽기 때문에 Bagging(RandomForest)나 Boosting Ensemble Model을 사용해 과적합을 피한다.
  • RandomForest의 장점은 Hyperparameter에 상대적으로 덜 민감한 것인데, Gradiant Boosting의 경우 Hyperparameter의 setting에 따라 RandomForest보다 좋은 예측 성능을 보여준다.

Boosting과 Bagging의 차이점

  • 가장 큰 차이는 RandomForest의 경우 각 Tree를 독립적으로 만들지만 Boosting은 만들어지는 Tree가 이전에 만들어진 Tree에 영향을 받는다는 것이다.
  • AdaBoost는 각 Tree(Weak learners)가 만들어질 때 잘못 분류되는 관측치에 Weight을 준다.
  • 다음 Tree가 만들어질 때 이전에 잘못 분류된 관측치가 더 많이 Sampling되게 하여 그 관측치를 분류하는데 더 초점을 맞춘다.

스크린샷 2021-08-26 13 27 24

  • AdaBoost Algorithm
    1. 모든 관측치의 Weight을 동일하게 Setting한다.
    2. 관측치 복원추출하여 Leak learners $Dn$을 학습하고 +,- 분류한다.
    3. 잘못 분류된 관측치에 Weight을 부여해 다음 과정에서 Sampling이 잘되게 한다.
    4. 2-3 과정을 $n$회 반복한다.
    5. 분류기($D1, D2, D3$)를 결합하여 최종 예측을 수행한다.

스크린샷 2021-08-26 13 27 52

  • Final learner H(x)Weak learners($h_t$)의 가중($\alpha$)합으로 만들어진다.
    • 여기서 $\alpha_t$ 가 크면 $e_t$가 작다는 것으로 분류기 $h_t$ 성능이 좋다는 것
    • 여기서 $\alpha_t$ 가 작으면 $e_t$가 크다는 것으로 분류기 $h_t$ 성능이 안좋다는 뜻

Gradiant Boosting

  • Regressor, Classifier 모두 사용할 수 있다.

스크린샷 2021-08-26 13 32 26

  • Gradiant는 Ada와 유사하지만 Loss function을 최소화 하는 방법에서 차이가 난다.
  • Gradiant에서는 Sample의 Weight을 조정하는 대신 Residual(잔차)을 학습한다.
  • 잔차가 더 큰 데이터를 학습하는 효과가 있다.

Python libraries for Gradient Boosting

  • scikit-learn Gradient Tree Boosting — 상대적으로 속도가 느리다.
    • Anaconda: already installed
    • Google Colab: already installed
  • xgboost — 결측값을 수용하며, monotonic constraints를 강제한다.
    • Anaconda, Mac/Linux: conda install -c conda-forge xgboost
    • Windows: conda install -c anaconda py-xgboost
    • Google Colab: already installed
  • LightGBM — 결측값을 수용하며, monotonic constraints를 강제한다.
    • Anaconda: conda install -c conda-forge lightgbm
    • Google Colab: already installed
  • CatBoost — 결측값을 수용하며, categorical features를 전처리 없이 사용한다.
    • Anaconda: conda install -c conda-forge catboost
    • Google Colab: pip install catboost

XGBoost

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from xgboost import XGBClassifier

pipe = make_pipeline(
    OrdinalEncoder(),
    SimpleImputer(strategy='median'),
    XGBClassifier(n_estimators=200
                  , random_state=2
                  , n_jobs=-1
                  , max_depth=7
                  , learning_rate=0.2
                 )
)

pipe.fit(X_train, y_train);

from sklearn.metrics import accuracy_score
y_pred = pipe.predict(X_val)
print('검증 정확도: ', accuracy_score(y_val, y_pred))

print(classification_report(y_pred, y_val))
'''
검증 정확도:  0.7601707982445736
              precision    recall  f1-score   support

           0       0.79      0.77      0.78      4724
           1       0.72      0.74      0.73      3707

    accuracy                           0.76      8431
   macro avg       0.76      0.76      0.76      8431
weighted avg       0.76      0.76      0.76      8431
'''
  • XGBoost는 RandomForest보다 Hyperparameter setting에 민감하다.

Early Stopping

  • n_estimators를 최적화 하기 위해 GridSeachCV나 for문 대신 Early stopping을 사용한다.
  • n_iterations가 반복수라 할때 Early stopping을 사용하면 n_interation 만큼의 Tree를 학습하면 된다.
  • GridSearchCV나 for문을 사용하면 sum(range(1,n_rounds+1))만큼의 Tree를 학습해야 하기 때문에(max_depthlearning_rate가 있으면 더하다.) Early stopping을 활용하는 게 효과적이다.
  • Target imbalance 시 Class에 Weigt을 주기 위해 Ratio를 계산한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
encoder = OrdinalEncoder()
X_train_encoded = encoder.fit_transform(X_train) # 학습데이터
X_val_encoded = encoder.transform(X_val) # 검증데이터

model = XGBClassifier(
    n_estimators=1000,  # <= 1000 트리로 설정했지만, early stopping 에 따라 조절됨
    max_depth=7,        # default=3, high cardinality 특성을 위해 기본보다 높임
    learning_rate=0.2,
    #scale_pos_weight=ratio, # imbalance 데이터 일 경우 비율적용
    n_jobs=-1
)

eval_set = [(X_train_encoded, y_train), 
            (X_val_encoded, y_val)]

model.fit(X_train_encoded, y_train, 
          eval_set=eval_set,
          eval_metric='error', # (wrong cases) / # (all cases)
          early_stopping_rounds=50
         ) # 50 rounds 동안 스코어의 개선이 없으면 멈춤
'''
[0]	validation_0-error:0.23978	validation_1-error:0.24801
Multiple eval metrics have been passed: 'validation_1-error' will be used for early stopping.

Will train until validation_1-error hasn't improved in 50 rounds.
[1]	validation_0-error:0.23509	validation_1-error:0.24564
[2]	validation_0-error:0.22940	validation_1-error:0.24268
[3]	validation_0-error:0.22830	validation_1-error:0.24173
[4]	validation_0-error:0.22575	validation_1-error:0.23900
[5]	validation_0-error:0.22409	validation_1-error:0.23817
[6]	validation_0-error:0.22258	validation_1-error:0.23663
[7]	validation_0-error:0.22098	validation_1-error:0.23627
[8]	validation_0-error:0.22089	validation_1-error:0.23734
[9]	validation_0-error:0.21893	validation_1-error:0.23627
[10]	validation_0-error:0.21691	validation_1-error:0.23485
[11]	validation_0-error:0.21626	validation_1-error:0.23508
[12]	validation_0-error:0.21419	validation_1-error:0.23437
[13]	validation_0-error:0.21261	validation_1-error:0.23331
[14]	validation_0-error:0.21101	validation_1-error:0.23354
[15]	validation_0-error:0.21009	validation_1-error:0.23212
[16]	validation_0-error:0.20888	validation_1-error:0.23224
[17]	validation_0-error:0.20769	validation_1-error:0.23295
[18]	validation_0-error:0.20627	validation_1-error:0.23236
[19]	validation_0-error:0.20473	validation_1-error:0.23271
[20]	validation_0-error:0.20393	validation_1-error:0.23200
[21]	validation_0-error:0.20298	validation_1-error:0.23188
[22]	validation_0-error:0.20179	validation_1-error:0.23105
[23]	validation_0-error:0.20061	validation_1-error:0.23129
[24]	validation_0-error:0.19954	validation_1-error:0.23117
[25]	validation_0-error:0.19865	validation_1-error:0.23046
[26]	validation_0-error:0.19758	validation_1-error:0.23176
[27]	validation_0-error:0.19660	validation_1-error:0.23188
[28]	validation_0-error:0.19524	validation_1-error:0.23141
[29]	validation_0-error:0.19503	validation_1-error:0.23129
[30]	validation_0-error:0.19370	validation_1-error:0.23271
[31]	validation_0-error:0.19293	validation_1-error:0.23236
[32]	validation_0-error:0.19180	validation_1-error:0.23259
[33]	validation_0-error:0.19014	validation_1-error:0.23070
[34]	validation_0-error:0.18892	validation_1-error:0.23034
[35]	validation_0-error:0.18862	validation_1-error:0.22951
[36]	validation_0-error:0.18753	validation_1-error:0.23034
[37]	validation_0-error:0.18622	validation_1-error:0.23153
[38]	validation_0-error:0.18524	validation_1-error:0.23034
[39]	validation_0-error:0.18471	validation_1-error:0.23046
[40]	validation_0-error:0.18379	validation_1-error:0.22987
[41]	validation_0-error:0.18344	validation_1-error:0.23022
[42]	validation_0-error:0.18266	validation_1-error:0.23283
[43]	validation_0-error:0.18222	validation_1-error:0.23354
[44]	validation_0-error:0.18115	validation_1-error:0.23390
[45]	validation_0-error:0.17991	validation_1-error:0.23366
[46]	validation_0-error:0.17955	validation_1-error:0.23437
[47]	validation_0-error:0.17842	validation_1-error:0.23402
[48]	validation_0-error:0.17777	validation_1-error:0.23307
[49]	validation_0-error:0.17700	validation_1-error:0.23283
[50]	validation_0-error:0.17629	validation_1-error:0.23402
[51]	validation_0-error:0.17513	validation_1-error:0.23449
[52]	validation_0-error:0.17442	validation_1-error:0.23437
[53]	validation_0-error:0.17442	validation_1-error:0.23461
[54]	validation_0-error:0.17294	validation_1-error:0.23331
[55]	validation_0-error:0.17214	validation_1-error:0.23414
[56]	validation_0-error:0.17184	validation_1-error:0.23414
[57]	validation_0-error:0.17128	validation_1-error:0.23508
[58]	validation_0-error:0.16983	validation_1-error:0.23461
[59]	validation_0-error:0.16890	validation_1-error:0.23402
[60]	validation_0-error:0.16819	validation_1-error:0.23378
[61]	validation_0-error:0.16760	validation_1-error:0.23425
[62]	validation_0-error:0.16686	validation_1-error:0.23508
[63]	validation_0-error:0.16597	validation_1-error:0.23366
[64]	validation_0-error:0.16526	validation_1-error:0.23366
[65]	validation_0-error:0.16413	validation_1-error:0.23366
[66]	validation_0-error:0.16336	validation_1-error:0.23366
[67]	validation_0-error:0.16289	validation_1-error:0.23354
[68]	validation_0-error:0.16259	validation_1-error:0.23390
[69]	validation_0-error:0.16223	validation_1-error:0.23342
[70]	validation_0-error:0.16194	validation_1-error:0.23259
[71]	validation_0-error:0.16123	validation_1-error:0.23283
[72]	validation_0-error:0.16060	validation_1-error:0.23402
[73]	validation_0-error:0.15980	validation_1-error:0.23342
[74]	validation_0-error:0.15939	validation_1-error:0.23283
[75]	validation_0-error:0.15900	validation_1-error:0.23342
[76]	validation_0-error:0.15820	validation_1-error:0.23295
[77]	validation_0-error:0.15749	validation_1-error:0.23354
[78]	validation_0-error:0.15672	validation_1-error:0.23319
[79]	validation_0-error:0.15589	validation_1-error:0.23307
[80]	validation_0-error:0.15559	validation_1-error:0.23247
[81]	validation_0-error:0.15458	validation_1-error:0.23283
[82]	validation_0-error:0.15408	validation_1-error:0.23319
[83]	validation_0-error:0.15369	validation_1-error:0.23271
[84]	validation_0-error:0.15283	validation_1-error:0.23295
[85]	validation_0-error:0.15233	validation_1-error:0.23354
Stopping. Best iteration:
[35]	validation_0-error:0.18862	validation_1-error:0.22951

XGBClassifier(base_score=0.5, booster=None, colsample_bylevel=1,
              colsample_bynode=1, colsample_bytree=1, gamma=0, gpu_id=-1,
              importance_type='gain', interaction_constraints=None,
              learning_rate=0.2, max_delta_step=0, max_depth=7,
              min_child_weight=1, missing=nan, monotone_constraints=None,
              n_estimators=1000, n_jobs=-1, num_parallel_tree=1, random_state=0,
              reg_alpha=0, reg_lambda=1, scale_pos_weight=1, subsample=1,
              tree_method=None, validate_parameters=False, verbosity=None)
'''

results = model.evals_result()
train_error = results['validation_0']['error']
val_error = results['validation_1']['error']

epoch = range(1, len(train_error)+1)
plt.plot(epoch, train_error, label='Train')
plt.plot(epoch, val_error, label='Validation')
plt.ylabel('Classification Error')
plt.xlabel('Model Complexity (n_estimators)')
plt.ylim((0.15, 0.25)) # Zoom in
plt.legend();

스크린샷 2021-08-26 14 15 21

1
2
3
4
5
6
7
8
9
10
11
12
13
14
print('검증 정확도', model.score(X_val_encoded, y_val))

print(classification_report(y_val, model.predict(X_val_encoded)))
'''
검증 정확도 0.7704898588542285
              precision    recall  f1-score   support

           0       0.78      0.81      0.79      4608
           1       0.76      0.73      0.74      3823

    accuracy                           0.77      8431
   macro avg       0.77      0.77      0.77      8431
weighted avg       0.77      0.77      0.77      8431
'''

Hyperparameter Tuning

Random Forest

  • max_depth (높은값에서 감소시키며 튜닝, 너무 깊어지면 과적합)
  • n_estimators (적을경우 과소적합, 높을경우 긴 학습시간)
  • min_samples_leaf (과적합일경우 높임)
  • max_features (줄일 수록 다양한 트리생성, 높이면 같은 특성을 사용하는 트리가 많아져 다양성이 감소)
  • class_weight (imbalanced 클래스인 경우 시도)

XGBoost

  • learning_rate (학습 속도, 높을경우 과적합 위험)
  • max_depth (낮은값에서 증가시키며 튜닝, 너무 깊어지면 과적합위험, -1 설정시 제한 없이 분기, 특성이 많을 수록 깊게 설정)
  • n_estimators (트리 수, 너무 크게 주면 긴 학습시간, early_stopping_rounds와 같이 사용)
  • scale_pos_weight (imbalanced 문제인 경우 적용시도)

참고자료

0%