Post

Feature Importance

모델의 Feature Importance를 확인하는 방법을 알아보자.

✅ Feature Importance

변수 중요도 : 모델 전체에서 어떤 feature가 중요할까? feature와 예측 결과 간의 관계이며, 당연히 성능이 좋은 모델이 아니라면 이 작업은 무의미하다.

✔️ Tree Based Model

Tree 기반 모델은 Feature Importance를 제공한다. Decision Tree, Random Forest, XGB … 등등.

✔ Decision Tree

Decision Tree에서는 Mean Decrease Impurity(MDI)로 표현한다. Tree 전체에 대해서, feature 별로 Information Gain의 (가중) 평균을 계산한다. (Information Gain : 지니 불순도가 감소하는 정도.)

✔ Random Forest

Random Forest에서는 각 트리 모델의 변수 중요도의 평균이다.

✔ XGB

XGBoost에서는 변수 중요도를 계산하는 3가지 방법이 있다.

  • weight
    • 모델 전체에서 해당 feature가 split 할 때 사용된 횟수의 합
    • plot_importance에서의 기본값
  • gain
    • feature 별 평균 information gain
    • model.feature_importances_의 기본값
    • total_gain : feature 별 information gain의 총 합
  • cover
    • feature가 split 할 때 샘플 수의 평균
    • total_cover : 샘플수의 총 합

feature importance plot 함수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 변수 중요도 plot
def plot_feature_importance(importance, names, topn = 'all'):
    feature_importance = np.array(importance)
    feature_names = np.array(names)

    data={'feature_names':feature_names,'feature_importance':feature_importance}
    fi_temp = pd.DataFrame(data)

    fi_temp.sort_values(by=['feature_importance'], ascending=False,inplace=True)
    fi_temp.reset_index(drop=True, inplace = True)

    if topn == 'all' :
        fi_df = fi_temp.copy()
    else :
        fi_df = fi_temp.iloc[:topn]

    plt.figure(figsize=(10,8))
    sns.barplot(x='feature_importance', y='feature_names', data = fi_df)

    plt.xlabel('importance')
    plt.ylabel('feature names')
    plt.grid()

    return fi_df

Decision Tree

1
2
3
4
5
6
7
8
from sklearn.tree import DecisionTreeRegressor, plot_tree
model = DecisionTreeRegressor()
model.fit(x_train, y_train)

# 모델 시각화
plt.figure(figsize = (20, 8))
plot_tree(model, feature_names = x.columns,
          filled = True, fontsize = 10);

output_4_0

1
2
# 변수 중요도
result = plot_feature_importance(model.feature_importances_, list(x))

output_5_0

Random Forest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from sklearn.ensemble import RandomForestRegressor
n_est = 3 # 시각화를 위해 3으로 진행
model = RandomForestRegressor(n_estimators = n_est, max_depth=2)
model.fit(x_train, y_train)

fn=list(x_train)
cn=["0","1"]
fig, axes = plt.subplots(nrows = 1,ncols = n_est,figsize = (24,4))
for index in range(0, n_est):
    plot_tree(model.estimators_[index],
                   feature_names = fn, 
                   class_names=cn,
                   filled = True, fontsize = 10,
                   ax = axes[index]);
    axes[index].set_title('Estimator: ' + str(index), fontsize = 12)
    
plt.tight_layout()
plt.show()

output_7_0

1
2
3
4
n_est = 50
model = RandomForestRegressor(n_estimators = n_est)
model.fit(x_train, y_train)
result = plot_feature_importance(model.feature_importances_, list(x))

output_8_0

XGB

1
2
3
4
5
6
7
8
from xgboost import XGBRegressor, plot_tree, plot_importance
model = XGBRegressor(n_estimators = 10, max_depth = 2)
model.fit(x_train, y_train)

# graphviz가 설치되어야 할 수 있는 시각화
# plt.rcParams['figure.figsize'] = 20,20
# plot_tree(model)
# plt.show()
XGBRegressor(base_score=0.5, booster='gbtree', callbacks=None,
             colsample_bylevel=1, colsample_bynode=1, colsample_bytree=1,
             early_stopping_rounds=None, enable_categorical=False,
             eval_metric=None, feature_types=None, gamma=0, gpu_id=-1,
             grow_policy='depthwise', importance_type=None,
             interaction_constraints='', learning_rate=0.300000012, max_bin=256,
             max_cat_threshold=64, max_cat_to_onehot=4, max_delta_step=0,
             max_depth=2, max_leaves=0, min_child_weight=1, missing=nan,
             monotone_constraints='()', n_estimators=10, n_jobs=0,
             num_parallel_tree=1, predictor='auto', random_state=0, ...)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
1
2
3
4
# plot_importance 의 변수중요도 기본값은 weight
plt.rcParams['figure.figsize'] = 8, 5
plot_importance(model)
plt.show()

output_11_0

1
2
# model.feature_importances_ : 변수중요도 기본값은 gain
result = plot_feature_importance(model.feature_importances_, list(x),4)

output_12_0

1
2
3
# importance_type = 'cover', 마찬가지로 'weight', 'gain' 됨
plot_importance(model, importance_type='cover')
plt.show()

output_13_0

✔️ Permutation Feature Importance(PFI)

알고리즘과 상관 없이 변수 중요도를 파악할 수 있는 방법

  • Feature 하나의 데이터를 무작위로 섞을 때, model의 score가 얼마나 감소되는지 계산

✔ PFI 알고리즘 구조

특정 feature $j$에 대해서 여러 번($K$) 섞고 계산해서 나온 score의 평균을 Base Line Score에서 빼서 최종 중요도($i$)를 계산한다.

\[\Large i_j = s - \frac{1}{K}\sum_{k=1}^K s_{k,j}\]

단점 : 만약 다중 공선성이 있는 변수가 존재하면, score가 별로 줄어들지 않을 수 있음

시각화는 BoxPlot이 가장 잘 보이므로 추천!

✔ SVM

1
2
3
4
5
from sklearn.inspection import permutation_importance
model1 = SVR()
model1.fit(x_train_s, y_train)
pfi1 = permutation_importance(model1, x_val_s, y_val, n_repeats=10, 
                              scoring = 'r2', random_state=20)
1
2
3
4
5
6
sorted_idx = pfi1.importances_mean.argsort()
plt.figure(figsize = (10, 8))
plt.boxplot(pfi1.importances[sorted_idx].T, vert=False, labels=x.columns[sorted_idx])
plt.axvline(0, color = 'r')
plt.grid()
plt.show()

output_18_0

1
2
3
4
5
6
7
plt.figure(figsize = (10,8))
for i,vars in enumerate(list(x)) :
    sns.kdeplot(pfi1.importances[i], label = vars)

plt.grid()
plt.legend()
plt.show()

output_17_0

평균값으로 변수 중요도 그래프 그리기

1
result = plot_feature_importance(pfi1.importances_mean, list(x_train))

output_19_0

✔ Deep Learning

딥러닝 모델에도 그대로 적용 가능하나, 딥러닝 모델에 대해서는 permutation_importance 함수를 사용할 때, 명시적으로 scoring='r2'를 지정해줘야 한다.

This post is licensed under CC BY 4.0 by the author.

Class Imbalance

Shapley Value와 SHAP