인프런 커뮤니티 질문&답변

Idea님의 프로필 이미지
Idea

작성한 질문수

[개정판] 파이썬 머신러닝 완벽 가이드

피처 중요도 시각화 plot_importance() 질문입니다.

해결된 질문

작성

·

5.8K

0

안녕하세요.

아래와 같이 피쳐 중요도를 시각화하면,  강사님 말씀대로 y축의 피처 명들이 출력되지 않습니다.

from xgboost import plot_importance

import matplotlib.pyplot as plt

%matplotlib inline

fig, ax = plt.subplots(figsize = (10, 12))

plot_importance(xgb_wrapper, ax = ax)

그래서 구글링을 해서 찾아보니 set_yticklabels라는게 있더군요. 코드를 다음과 같이 변경하니 피처 명들이 나오긴 하는데, 이게 맞는 방법인지 확신이 안서서 질문드립니다.

from xgboost import plot_importance

import matplotlib.pyplot as plt

%matplotlib inline

fig, ax = plt.subplots(figsize = (10, 12))

plot_importance(xgb_wrapper, ax = ax).set_yticklabels(dataset.feature_names)

답변 6

1

권 철민님의 프로필 이미지
권 철민
지식공유자

위 코드는 확인해보니 사이킷런 wrapper의 feature_importances_ 값과 xgboost의 피처별 f1 score를 뽑아내는 로직이 서로 달라서 안맞는 것이었군요.

그리고 set_yticklabels() 를 이용하는 방식을 저도 stackoverflow에서 찾았는데, 답변하신 분이 잘못 생각하신것 같습니다. set_ysticklabels()안에 f1 score 별로 feature 들을 정렬해서 입력해야 하는데, 단순하게 컬럼명만 입력해서는 안됩니다.

https://stackoverflow.com/questions/46943314/xgboost-plot-importance-doesnt-show-feature-names

 f1 score 별로 feature들을 정렬해 주려면, xgboost 모듈내에서 이를 지원하는 api가 있으면 좋을 텐데 저는 찾지 못했습니다.

결론적으로 말씀드리면 사이킷런 xgboost wrapper를 사용하실 때에는 앞에 말씀드린 DataFrame을 피처 데이터 세트로 이용하거나 python xgboost를 사용하실때는 아래와 같이 DMatrix를 만들때 feature names을 인자로 입력하는 방법중 하나를 선택하면 될 것 같습니다.

import xgboost as xgb
from xgboost import plot_importance

import pandas as pd
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
import warnings
warnings.filterwarnings('ignore')

dataset = load_breast_cancer()
X_features= dataset.data
y_label = dataset.target

cancer_df = pd.DataFrame(data=X_features, columns=dataset.feature_names)
cancer_df['target']= y_label

X_train, X_test, y_train, y_test=train_test_split(X_features, y_label,
                                         test_size=0.2, random_state=156 )

# DMatrix 생성 시 인자로 feature_names를 입력
dtrain = xgb.DMatrix(data=X_train , label=y_train, feature_names=dataset.feature_names)
dtest = xgb.DMatrix(data=X_test , label=y_test, feature_names=dataset.feature_names)

params = { 'max_depth':3,
           'eta': 0.1,
           'objective':'binary:logistic',
           'eval_metric':'logloss',
           'early_stoppings':100
        }
num_rounds = 400

# train 데이터 셋은 ‘train’ , evaluation(test) 데이터 셋은 ‘eval’ 로 명기합니다.
wlist = [(dtrain,'train'),(dtest,'eval') ]
# 하이퍼 파라미터와 early stopping 파라미터를 train( ) 함수의 파라미터로 전달
xgb_model = xgb.train(params = params , dtrain=dtrain , num_boost_round=num_rounds , evals=wlist )

import matplotlib.pyplot as plt
%matplotlib inline

fig, ax = plt.subplots(figsize=(10, 12))
plot_importance(xgb_model, ax=ax)

1

권 철민님의 프로필 이미지
권 철민
지식공유자

안녕하십니까,

plot_importance()를 사용할 때 컬럼명이 안나오는것은 feature 데이터 세트가 numpy 이기 때문입니다. feature 데이터 세트를 DataFrame으로 바꾸면 컬럼명이 나옵니다. 그런데 Xgboost의 경우는 feature 데이터 세트를 numpy로 하는게 더 좋습니다. DataFrame으로 하다보면, 이유를 알 수 없는 버그가 발생합니다. 특히 복잡한 데이터 가공을 xgboost와 함께 진행하다보면 이렇게 발생하는 버그 때문에 많은 시간을 소모할 수 있습니다. 아래는 plot_importance() 를 DataFrame으로 feature 데이터 세트를 만들었을 때의 코드 입니다. 

import xgboost as xgb
from xgboost import plot_importance
from xgboost import XGBClassifier

import pandas as pd
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
import warnings
import matplotlib.pyplot as plt
%matplotlib inline
warnings.filterwarnings('ignore')

dataset = load_breast_cancer()
X_features= dataset.data
y_label = dataset.target

cancer_df = pd.DataFrame(data=X_features, columns=dataset.feature_names)
cancer_df['target']= y_label

X_features = cancer_df.iloc[:, :-1]
y_label = cancer_df.iloc[:, -1]

# 전체 데이터 중 80%는 학습용 데이터, 20%는 테스트용 데이터 추출
X_train, X_test, y_train, y_test=train_test_split(X_features, y_label,
                                         test_size=0.2, random_state=156 )
print(X_train.shape , X_test.shape)

xgb_wrapper = XGBClassifier(n_estimators=400, learning_rate=0.1, max_depth=3)

evals = [(X_test, y_test)]
xgb_wrapper.fit(X_train, y_train, early_stopping_rounds=100, eval_metric="logloss",
                eval_set=evals, verbose=True)

ws100_preds = xgb_wrapper.predict(X_test)
ws100_pred_proba = xgb_wrapper.predict_proba(X_test)[:, 1]


fig, ax = plt.subplots(figsize=(10, 12))
# 사이킷런 래퍼 클래스를 입력해도 무방.
plot_importance(xgb_wrapper, ax=ax)

감사합니다.

0

안녕하세요 강사님,

첫번째 답변에서, Xgboost는 feature 데이터 세트가 numpy로 하는 게 좋다고 하셨는데, 그럼  DataFrame으로 말고 numpy 형태로 놔두는 것이 좋은 건가요? 아니면 Datafraom으로 바꾸는 것이 좋은 건가요?

권 철민님의 프로필 이미지
권 철민
지식공유자

안녕하십니까, 

옛날 버전 xgboost는 numpy로 하는게 더 좋은데, 지금은 버전업이 되어서 DataFrame으로 바꿔도 별 문제가 없군요. 

아하! 그렇군요! 빠른 답변감사합니다! DataFrame으로 해보겠습니다~!

0

Idea님의 프로필 이미지
Idea
질문자

감사합니다!

저도 올려주신 stackoverflow를 참고해서 질문 드렸는데, 그 답변자 분께서 해주신 설명이 좀 이상해서 질문드렸던 겁니다.

앞으로는 알려주신 방법을 참고하겠습니다.

0

권 철민님의 프로필 이미지
권 철민
지식공유자

방법이 있을거 같아서 아래와 같이 코드를 수행해 봤는데, 결과가 위 코드랑 다르군요. 참고 부탁드립니다.

import seaborn as sns

ftr_importances_values = xgb_wrapper.feature_importances_
ftr_importances = pd.Series(ftr_importances_values,index=X_train.columns  )
ftr_top20 = ftr_importances.sort_values(ascending=True)

fig, ax = plt.subplots(figsize = (10, 12))

plot_importance(xgb_wrapper, ax = ax).set_yticklabels(ftr_top20.index)

0

Idea님의 프로필 이미지
Idea
질문자

답변 감사드립니다.

추가적으로 제가 질문드린 set_yticklabels()를 이용해서 해결할 수 있는 방법은 혹시 없을까요?

Idea님의 프로필 이미지
Idea

작성한 질문수

질문하기