오늘은 아래 내용을 배웠다.
KeyWords
Interpreting_ML_Models
- PDP (Patial Dependent Plot, 부분의존도)
- SHAP
- 참고로 이것들은 model-agnostic, 즉 어떤 모델이건 상관없이 사용할 수 있다.
이 개념을 어떤 맥락에서 배웠나?
Feature Importance
를 쉽게 구할 수 있었는데(model.feature_importance_
), 이건 어떤 특성이 모델의 성능에 있어 중요하며 많이 쓰이는지를 알려주긴 하지만, 어떻게 영향을 주는지는 알려주지 않는다. (피쳐의 값에 따라 타겟값이 증가/감소하는지와 같은 관계를 말함)PDP
While feature importance shows what variables most affect predictions, partial dependence plots show how a feature affects predictions.
=> 사실 이 말 하나면 PDP의 사용 목적은 다 설명이 되는 것 같다. (출처)
전체 관측치에 대하여 특성과 타겟 간의 관계를 설명할 수 있다.
관심있는 한 가지 특성에 대해서만 볼 수도 있고, 2개 이상에 대해서도 볼 수 있다.
pdp_isolate
ICE(Individual Condition Expectation) Curves
라는 개념이 나오는데, 이 곡선은 하나의 관측치에 대해 관심있는 그 특성을 변화시킴에 따른 타겟 예측값의 변화곡선을 말한다.pdp_interact
SHAP Value plot
You've seen (and used) techniques to extract general insights from a machine learning model. But what if you want to break down how the model works for an individual prediction? + 만약 은행에서 모델을 통해 특정 고객을 대출 거부로 결정하였는데, 해당 고객에게 왜 대출 거부로 분류되었는지 설명해야 한다면 어떻게 할 것인가? (출처)
Shapley Value
(혹은 줄여서 shap value
)를 계산하여 이루어지는데, 특성 수가 많을 수록 계산량이 기하급수적으로 늘어나므로, 적절한 샘플링을 통해 근사적으로 값을 구해야 한다!Base Value
라고 하여 전체 샘플에 대한 예측값의 평균도 보여준다. summary plot
을 통해 알 수 있다. LSTAT
특성이 가장 영향이 큰 것을 알 수 있다. 가운데 빨간색과 파란색 점이 몰려있는 걸 보면, 정확한 양음의 상관관계가 없겠구나 알 수 있다. plot_type
이란 파라미터를 통해서 violin, bar등 여러가지 형태로 그려볼 수 있다. SHAP_summary_plot 응용에 대해 질문드립니다. 선택한 샘플들에 대한 피쳐와 타겟과의 관계를 볼 수 있다는 점은 이해했습니다. 그러면 만약 개별 고객에 대한 쇼핑 정보를 담고 있는 데이터에 이걸 사용해본다고 했을 때요. 단순히 100명의 고객을 샘플링하여 summaryplot을 보는 것보다는, 오늘 과제의 보스턴 데이터에서 하나의 샘플이 하나의 구획에 대한 평균 정보를 담고 있는 것처럼, 각 고객들을 '회원 등급'으로 임의로 클러스터링?하면(=한 행에는 한 회원등급의 평균 쇼핑정보가 담김), 각 회원등급별로 피쳐와 타겟의 영향력이 어떻게 다른지 보는데 활용할 수 있겠다는 생각이 들었습니다. 제가 잘 이해한게 맞을까요? 이런 생각을 하게된 이유가, 만약 오늘 보스턴 데이터의 각 샘플 하나가 '구획 하나'가 아니었다면, 단순히 100개 샘플링하여 summary plot을 그리는게 과연 어떤 의미가 있을지 싶어서였습니다.
내가 잘 못 이해한 부분은 없는 것 같았고, 내가 뭘 보고 싶은지에 따라서 활용 방향이 천차만별이겠구나~ 라는 결론을 내렸다.
오늘 실습한 코드만 그대로 옮겨둔다
어차피 open된 데이터셋을 사용했기 때문에 괜찮을 것 같다.
데이터셋은 Shap.datasets.boston()
이다.
import sklearn
import xgboost
import shap
from sklearn.model_selection import train_test_split
shap.initjs();
df, target = shap.datasets.boston()
X_train,X_test,y_train,y_test = train_test_split(df, target, test_size=0.2, random_state=2)
model = xgboost.XGBRegressor().fit(X_train, y_train)
### Draw PDP plots ### - 직접 작성한 부분 시작
from pdpbox.pdp import pdp_isolate, pdp_plot, pdp_interact, pdp_interact_plot
# 한가지 특성 - 'AGE' & target
feature = 'AGE'
isolated = pdp_isolate( #공식문서 https://pdpbox.readthedocs.io/en/latest/pdp_isolate.html
model = model,
dataset = X_train,
model_features = X_train.columns,
feature = feature,
grid_type='percentile',
num_grid_points=50
)
pdp_plot(isolated, feature_name=feature);
output
# 두가지 특성 & 타겟 ('AGE', 'RM)
features = ['AGE', 'RM']
interaction = pdp_interact(
model = model,
dataset = X_train,
model_features = X_train.columns,
features = features
)
pdp_interact_plot(interaction, feature_names = features, plot_type = 'grid') # type of the interact plot, can be ‘contour’ or ‘grid’
output
### (Urclass Quiz) 이곳에서 과제를 진행해 주세요 ###
explainer = shap.TreeExplainer(model) #tree model의 shap values 확인 객체 생성
shap.initjs(); #이거 셀에 안 넣으면 JS 작동 안하는 듯.
### Draw SHAP plots ###
# 첫번째 샘플을 가지고 shap force_plot를 그려보자
row = X_train.iloc[[1]] #사용할 샘플
shap_values = explainer.shap_values(row) #shap values 계산
shap.force_plot(
base_value=explainer.expected_value,
shap_values=shap_values,
features=row
)
# SHAP_2 - force plot 그려보자.
shap.initjs();
rows = X_train.iloc[:100] #샘플은 100개만
shap_values = explainer.shap_values(rows) #shap values 계산
shap.force_plot(explainer.expected_value, shap_values, rows)
#Summary plot 그려보기
shap.summary_plot(shap_values, rows) #동일한 샘플에 대해
2번 아웃풋은 상단 개념 부분에 넣은 그림을 보면 됨.
정리
서로 관련이 있는 모든 특성들에 대한 전역적인(Global) 설명
타겟과 관련이 있는 개별 특성들에 대한 전역적인 설명
개별 관측치에 대한 지역적인(local) 설명