본문 바로가기

Data Handling/Data Preprocessing

Feature selection : feature importance vs permutation importance

안녕하세요, 오늘은 Feature selection 에 대해 다뤄보려고 합니다!

Feature selection은 말 그대로 모델에 사용될 feature를 선택하는 과정입니다.

 

feature가 그냥 많으면 많을수록 좋은거 아닌구요?

네!! 아닙니다!!

예측에 도움이 되는 feature는 많으면 많을수록 좋지만, 어떤 특성들은 예측에 아무런 도움이 되지 않아 시간만 소모하기도 하고 또 어떤 특성들은 오히려 성능을 떨어뜨리기도 하기 때문에 제거해주는편이 좋습니다.

 

그럼 어떤 기준으로 중요한 특성과 그렇지 못한 특성으로 구분할까요?

오늘 소개해드릴 기준은 feature importancepermutation importance 입니다. 

 

 


순서

  1. feature importance 
    1. 개념 및 코드
    2. 동작 원리
  2. permutation importance
    1. 개념 및 코드
    2. 동작 원리

 


 

1. feature importance

1-1. 개념 및 코드

트리 기반 모델들(randomforest, xgboost, lightgbm 등)은 기본적으로 feature importance를 API 혹은 모델 내장 함수로 제공합니다.

따라서 API(plot_importance)를 import하거나 feature_importances_ 내장 함수를 이용해서 손쉽게 구현할 수 있습니다.

 

* 참고 코드

# API 사용
from xgboost import XGBClassifier
from xgboost import plot_importance

model = XGBClassifier(random_state=11)
model.fit(X_train, y_train)

plot_importance(model, max_num_features=20)

 

# 모델 내장 함수 사용
from xgboost import XGBClassifier

model = XGBClassifier(random_state=11)
model.fit(X_train, y_train)

# 배열형태로 반환
ft_importance_values = model.feature_importances_

# 정렬과 시각화를 쉽게 하기 위해 series 전환
ft_series = pd.Series(ft_importance_values, index = X_train.columns)
ft_top20 = ft_series.sort_values(ascending=False)[:20]

# 시각화
plt.figure(figsize=(8,6))
plt.title('Feature Importance Top 20')
sns.barplot(x=ft_top20, y=ft_top20.index)
plt.show()

 

아래 그림은 kaggle의 "타이타닉 생존자 예측 컴피티션"에서 사용된 feature importance 그림인데요,

생존자를 예측하는데 성별(Sex)과 좌석 등급(Pclass)이 많은 영향을 끼쳤다고 해석할 수 있습니다.

즉 해당 feature들을 잘 고려해야겠죠??

 

https://blogs.mathworks.com/loren/2015/06/18/getting-started-with-kaggle-data-science-competitions/

 

하지만 이 지표는 절대적인게 아닙니다.

중요도는 낮게 평가되었지만 실제로 중요한 특성일 수도 있고, 그렇기 때문에 제거했을 경우 성능이 떨어질 수도 있습니다. 즉 상위 n개의 특성들을 제외한 나머지 특성들을 모두 제거하는 방식은 바람직하지 못하죠!

따라서 feature importance를 고려하여 특성별로 A/B test 를 진행하며 feature selection 하시는 것을 추천합니다.

 

 

1-2. 동작 원리

왜 지표가 절대적이지 못할까요? 먼저 feature importance 가 동작하는 원리를 파악해봅시다!

 

feature importance는 트리기반 모델에서 사용됩니다.즉 중요도를 구분하는데에 트리의 분할과 밀접한 관련이 있다는 말인데요, 쉽게 생각하면 특정 feature가 트리를 분할하는데 얼마나 기여를 했는지에 따라 중요도가 결정되는 것입니다.

 

좀 더 자세히 들어가 볼까요? 트리가 분할하는 원리는 무엇일까요?트리는 순수도를 기준으로 분할하게 됩니다. 

즉 가장 잘 분류 시키는 feature를 순수도라는 기준으로 판단하는 것입니다.

 

예를 들어, '성별' 이라는 특성으로 분류했을때 고양이와 강아지를 잘 분류하지 못하고(순수도가 낮다), '눈동자 모양'이라는 특성으로 분류했을때 잘 분류한다면(순수도가 높다), '눈동자 모양'을 해당 트리 분할 기준으로 선택하는 것입니다.

그리고 '눈동자 모양'의 중요도가 높아지겠죠?

 

그럼 이 순수도 라는 것을 어떻게 계산하나요?

여기서 엔트로피gini 계수 라는 개념이 등장합니다.

 

 

1) 엔트로피를 이용한 트리분할

엔트로피의 계산 공식은 다음과 같습니다. 아래의 식으로 각 노드들의 순수도를 계산할 수 있습니다. 

하지만 각 노드들의 엔트로피 만으로는 특정 feature로 인한 순수도 변화량을 알지 못합니다. 

엔트로피 계산식

 

따라서 엔트로피를 활용하여 정보 이득량(information gain)을 계산합니다.

말 그대로 이 feature로 인한 정보 이득량이 얼마나 되는지 엔트로피로 계산하는 것입니다.

 

정보 이득 계산식(S: 부모노드 샘플, Sv: 자식노드 샘플)

 

 

2) gini 계수를 이용한 트리분할

지니계수의 계산 공식은 다음과 같습니다. 지니계수 역시 엔트로피와 마찬가지로 각 노드들의 순수도를 측정하는 하나의 척도 입니다.

gini 계수 계산식

 

지니계수 역시 노드의 순수도를 측정할 뿐, 어떤 feature가 중요한지는 파악할 수 없기 때문에 gini 계수를 활용하여 gini split 라는 것을 계산합니다. 그리고 가장 작은 gini split를 가진 특성을 기준으로 트리를 분할합니다.

 

gini split 계산식

 


 

 

이제 정리가 됩니다.

트리 분할은 순수도를 기준으로 하고, 이 순수도는 엔트로피 혹은 gini 계수로 계산합니다. 

더 나아가서 특정 feature의 중요도를 파악하기 위해 순수도의 변화량(?)을 계산하고, 이는 엔트로피를 활용한 정보이득량 혹은 gini 계수를 이용한 gini split로 고려될 수 있습니다.

이 때 '정보 이득량이 가장 높은' 혹은 'gini split이 가장 낮은' feature를 선택하여 트리를 분할하고, 중요도에 반영됩니다.

 

자 이제 다시 본론으로 돌아와서!!

feature importance는 왜 절대적인 지표가 되지 못할까요?

feature importance는 노드가 분기 할때의 정보 이득 혹은 지니 상수만을 고려하여 중요도를 부여하기 때문에 과적합에 대해 고려하지 못합니다.

 

예를 들어 동그라미와 세모를 분류하는데, 동그라미 집단 속에 하나의 세모가 있다고 가정합시다.

이 세모를 분리해내기 위해 여러가지 기준선을 추가하는 것이 과적합이라고 한다면, 트리에서도 이 동그라미 속에 있는 하나의 세모를 분리해내는 특성을 선택하는 것입니다(순수도는 높아지기 때문에).

이를 편향에 대해 학습했다고 하는데요! 이런 이유로 절대적인 지표가 되지 못한다고 할수 있습니다.

 

 

 

2. permutation importance

2-1. 개념 및 코드

permutation importance 는 feature 하나하나마다 shuffle을 하며 성능 변화를 지켜보고,

만약 그 feature가 모델링에서 중요한 역할을 하고 있었다면 성능이 크게 떨어질 것이라는 개념으로 출발합니다.

 

* 참고 코드

import eli5 
from eli5.sklearn import PermutationImportance 
from sklearn.ensemble import RandomForestClassifier

# 미리 사용할 알고리즘을 fit 해야한다
model = RandomForestClassifier().fit(X_train, y_train)

perm = PermutationImportance(model, scoring = "accuracy", random_state = 22).fit(X_val, y_val) 
eli5.show_weights(perm, top = 20, feature_names = X_val.columns.tolist())

 

결과값 예시 (https://www.kaggle.com/dansbecker/permutation-importance)

 

weight(성능 감소량)가 양수의 값을 가지는 변수들은 모델에 큰 영향을 끼친다는 의미이기 때문에 중요한 feature라고 판단할 수 있습니다.

반면 성능의 변화가 없거나(0), 음수의 값을 가지는 변수들은 모델에 큰 영향을 끼치지 못하는 즉 중요하지 않은 feature라고 판단할 수 있습니다.

 

위 예시는 축구선수 중 누가 '최고의 선수'로 선정될지 예측하는데 사용되는 변수들입니다.

permutation importance 의 결과값에 따르면 '골 득점(Goal score)'이 가장 중요한 변수이고, '패스(Passes)'가 가장 중요하지 않은 변수라고 판단했습니다. 

 

 

2-2. 동작 원리

10살 때의 정보로 20살이 됐을때의 키를 예측하는 예시를 들어보겠습니다.

변수들 중 하나인 '10살 때의 키' 정보만을 무작위로 섞어버리고 성능을 측정한다면 엄청나게 떨어질 것입니다.

모델과 상관없이 직관적으로 해당 변수가 결과값에 큰 영향을 미치고 있기 때문입니다.

 

반면 '10살 때의 양말 갯수'에 대한 정보를 무작위로 섞고 성능을 비교한다면 큰 차이가 없을 것입니다.

해당 변수가 20살의 키를 예측하는데 큰 영향을 미치지 못하기 때문입니다. 

 

 

shuffling 예시 (https://www.kaggle.com/dansbecker/permutation-importance)

 

이렇게 하나하나 feature를 섞고 성능을 비교하는 방법은 정확도 면에서 높은 타당성을 가지지만, 

시간이 오래 걸린다는 단점이 있기 때문에 feature의 갯수가 많다면 비효율적인 방법입니다.

 

또한 정확도가 높긴 하지만, 마찬가지로 절대적인 지표는 아니기 때문에 변수 선택을 할 때에는 반드시 A/B test를 해볼 것을 추천드립니다.