각각 특성을 모든 트리에 대해 평균 불순도 감소를 계산한 값
⚠️ sklearn 분류기에서 디폴트로 사용되는 특성 중요도는 속도는 빠르지만 결과를 주의해야한다
# 특성 중요도
# pipe 중 랜덤포레스트
rf = pipe.named_steps['randomforestclassifier']
# 데이터프레임으로 만들기
importances = pd.Series(rf.feature_importances_, X_train.columns)
# 시각화
importances.sort_values().plot.barh();
어느 한 특성을 매번 drop한 후 다시 fit하는 방법
⚠️ 이론적으로 가장 좋아보이는 방법이지만 매우 느리다
특성이 n개 존재할 때 n+1번 학습이 필요
R = 'AAAA' # 드롭할 특성
pipe.fit(X_train.drop(columns=R), y_train) # 드롭 후 fit
score1 = pipe.score(X_val.drop(columns=R), y_val) # 드롭 후 점수
pipe.fit(X_train, y_train) # 원래 모델
score2 = pipe.score(X_val, y_val)
순열 중요도는 기본 특성 중요도와 drop-column 중요도 중간에 위치하는 특징을 가진다
중요도 측정은 관심있는 특성에만 무작위로 노이즈를 주고 예측을 하였을 때 성능 평가지표(정확도, F1 score, R2 등)가 얼마나 감소하는지를 측정
ex) 특성의 값을 무작위로 섞기
index index
1526 very high → 1526 low
2689 high → 2689 medium
3951 low → 3951 very high
1497 very low → 1497 high
23685 medium → 23685 very low
전체적인 값의 분포는 변하지 않음
원리 : 검증데이터에서 각 특성을 제거하지 않고 특성값에 무작위로 노이즈를 주어 기존정보를 제거하여 특성이 기존에 하던 역할을 하지 못하게 하고 성능을 측정한다
이때 노이즈를 주는 가장 간단한 방법이 그 특성값들을 샘플들 내에서 섞는 것
import eli5
from eli5.sklearn import PermutationImportance
from sklearn.pipeline import Pipeline
# 중요도를 계산하기 전 인코딩과 분류모델을 분리하여 pipe로 지정
pipe = Pipeline([
('preprocessing', make_pipeline(OrdinalEncoder(), SimpleImputer())),
('RF', RandomForestClassifier(n_estimators=100, random_state=2, n_jobs=-1))
])
# permuter 정의
permuter = PermutationImportance(
pipe.named_steps['RF'], # pipeline 중 모델
scoring='accuracy', # 평가지표
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()
# 특성별 score 확인
eli5.show_weights(
permuter,
top=None, # top n 지정 가능, None 일 경우 모든 특성
feature_names=feature_names # list 형식
)
※ 중요도가 - 인 특성들은 제거해도 성능은 거의 영향이 없고 학습 속도가 개선이 된다