- 부분의존도그림(Partial dependence plot, PDP)을 시각화하고 해석할 수 있습니다.
- 개별 예측 사례를 Shap value plots을 사용해 설명할 수 있습니다.
- black box model이란?
* X-AI
- 모델이 어떻게 이런 예측을 했는지를 확인하기 위한 ( 예측모델 설명 )
*Partial Dependence Plots( PDP )
- ICE곡선들의 평균(= ICE 곡선은 하나의 관측치에 대해 관심 특성을 변화 시킴에 따른 타겟값 변화 곡선 )
- 복잡한 모델 -> 이해하기 어렵지만 성능이 좋다. ( 특성중요도가 긍정인지 부정인지 파악 어려움 )
- ==> so, PDP사용 = feature 가 target의 어떻게 영향을 미치는지 파악 가능
- 단순한 모델 -> 이해하기 쉽지만 성능이 부족하다. (ex 회귀계수 양의선형관계 / 음의선형관계 )
* PDP 1(= 1개의 특성과 타겟과의 관계 )
encoder = OrdinalEncoder()
X_train_encoded = encoder.fit_transform(X_train) # 학습데이터
X_val_encoded = encoder.transform(X_val) # 검증데이터
boosting = XGBRegressor(
n_estimators=1000,
objective='reg:squarederror', # default
learning_rate=0.2,
n_jobs=-1
)
eval_set = [(X_train_encoded, y_train),
(X_val_encoded, y_val)]
boosting.fit(X_train_encoded, y_train,
eval_set=eval_set,
early_stopping_rounds=50
)
from pdpbox.pdp import pdp_isolate, pdp_plot
feature = 'annual_inc'
isolated = pdp_isolate(
model=linear, # or boosting / model변수 지정에 따라 그래프 다름
dataset=X_val, # X_val_encoded = boosting은 인코딩함
model_features=X_val.columns, # X_val_encoded.columns
feature=feature,
grid_type='percentile', # default='percentile', or 'equal'
num_grid_points=10 # default=10
)
pdp_plot(isolated, feature_name=feature);
######################## ICE curve ##################
pdp_plot(isolated
, feature_name=feature
, plot_lines=True # ICE plots
, frac_to_plot=0.001 # or 10 (# 10000 val set * 0.001)
, plot_pts_dist=True)
* PDP 2 (= 두 특성간의 상호작용 )
from pdpbox.pdp import pdp_interact, pdp_interact_plot
features = ['annual_inc', 'fico_range_high']
interaction = pdp_interact(
model=boosting,
dataset=X_val_encoded,
model_features=X_val_encoded.columns,
features=features
)
pdp_interact_plot(interaction, plot_type='grid',
feature_names=features);
* Encoding 전 특성의 범주이름으로 확인하는법 ( PDP 1 )
#인코딩을 하게되면 학습 후 PDP 를 그릴 때 인코딩된 값이
#나오게 되어 카테고리특성의 실제 값을 확인하기 어려움
# 클래스가 male, female 경우 인코딩하면 1, 2 로 나옴
pipe = make_pipeline(
OrdinalEncoder(),
RandomForestClassifier(n_estimators=100, random_state=42, n_jobs=-1)
)
pipe.fit(X, y);
encoder = pipe.named_steps['ordinalencoder']
X_encoded = encoder.fit_transform(X)
rf = pipe.named_steps['randomforestclassifier']
feature = 'sex'
pdp_dist = pdp.pdp_isolate(model=rf, dataset=X_encoded, model_features=features, feature=feature)
pdp.pdp_plot(pdp_dist, feature) # male과 female이 1과 2로된 그래프로 나옴
encoder.mapping # 하면 인코딩된 칼럼들이 나옴
'''
[{'col': 'sex',
'mapping': male 1
female 2
NaN -2
dtype: int64,
'data_type': dtype('O')},
'''
# 추가하면 x축 male과 female로 바뀜
plt.xticks([1, 2], ['male', 'female',]);
##################### or #############
feature = 'sex'
for item in encoder.mapping:
if item['col'] == feature:
feature_mapping = item['mapping'] # Series
feature_mapping = feature_mapping[feature_mapping.index.dropna()]
category_names = feature_mapping.index.tolist()
category_codes = feature_mapping.values.tolist()
pdp.pdp_plot(pdp_dist, feature)
# xticks labels 설정을 위한 리스트를 직접 넣지 않아도 됩니다
plt.xticks(category_codes, category_names);
* PDP 2
features = ['sex', 'age']
interaction = pdp_interact(
model=rf,
dataset=X_encoded,
model_features=X_encoded.columns,
features=features
)
pdp_interact_plot(interaction, plot_type='grid', feature_names=features);
# sex 특성이 인코딩되서 나옴
pdp = interaction.pdp.pivot_table(
values='preds',
columns=features[0],
index=features[1]
)[::-1]
pdp = pdp.rename(columns=dict(zip(category_codes, category_names)))
plt.figure(figsize=(6,5))
sns.heatmap(pdp, annot=True, fmt='.2f', cmap='viridis')
plt.title('PDP decoded categorical');
*SHAP / gradCAM(= image)
어떤 머신러닝 모델이든지 단일 관측치로부터 특성들의 기여도(feature attribution)를 계산하기 위한 방법
모델을 모두 학습하고 평가한 후에 수행하는 "사후 분석" 방범 중 하나
- 그렇기 때문에 Shapley Value 결과만으로 어떤 변수로 인해 어떤 결과가 나왔다는 인과관계를 정립시킬 수 없다
(= 예측력에 주요하게 기여한 것은 맞지만 이를 일반화 시킬수는 없다.)
Shapley value 방법으로 계산된 설명은 항상 모든 특성을 사용한다. 사람들은 LIME과 같이 선택적인 설명을 선호한다. 비전문가가 사용하기에는 LIME이 더 적절한 설명 방법일 수 있다.
Shapley value는 LIME과 다르게 설명가능한 모델이 아닌 단순히 특성별 기여도를 나타내는 값이다. 즉 입력값의 변화에 따른 예측값의 변화를 설명하기 힘들다. 예를 들면 “내가 1년에 300 유로를 더 번다면 내 신용점수는 5 포인트만큼 오를거야”와 같은 설명이 불가능하다.
또 다른 단점으로는 새로운 데이터에 대해서 Shapley value를 계산할 때 생기는 문제점이다. 새로운 데이터에 대한 정보가 기존 데이터에 없게되면 이 값을 대체하기위한 진짜와 비슷한 가상의 데이터를 만들어야지만 이 문제를 해결할 수 있다.
https://techblog-history-younghunjo1.tistory.com/200
[ML] Explainable AI - Shapley Value
🔉해당 포스팅에서 사용된 자료는 고려대학교 산업경영공학부 김성범교수님의 Youtube 강의자료에 기반했음을 알려드립니다. 혹여나 출처를 밝혔음에도 불구하고 저작권의 문제가 된다면 joyh951
techblog-history-younghunjo1.tistory.com
https://datanetworkanalysis.github.io/2019/12/23/shap1
SHAP에 대한 모든 것 - part 1 : Shapley Values 알아보기
1. 게임이론 (Game Thoery) Shapley Value에 대해 알기위해서는 게임이론에 대해 먼저 이해해야한다. 게임이론이란 우리가 아는 게임을 말하는 것이 아닌 여러 주제가 서로 영향을 미치는 상황에서 서로
datanetworkanalysis.github.io

* Shapley values
게임이론에서 같은 팀 선수들(특성들)이 게임 목표(예측) 달성을 위해 각자 자신의 역할(기여)을 한다고 할 때 게임 목표 달성 후 받은 포상을 어떻게 하면 그들의 기여도에 따라 공평하게 나누어 줄 수 있을 것인가? 라는 질문과 연관됩니다.
==> 머신러닝의 특성 기여도(feature attribution) 산정에 활용

row = X_test.iloc[[1]] # 중첩 brackets을 사용하면 결과물이 DataFrame입니다
row
# 실제 집값
y_test.iloc[[1]] # 2번째 데이터를 사용했습니다
# 모델 예측값
model.predict(row)
import shap
explainer = shap.TreeExplainer(model) # 최적의 파라미터값으로 구한 model
# model = search.best_estimator_
shap_values = explainer.shap_values(row) # 각 특성의 기여도
shap.initjs()
shap.force_plot(
base_value=explainer.expected_value,
shap_values=shap_values,
features=row
)

==> target 값에 bathroom은 값을 올리고 / lat, bedrooms 은 값을 내리는데 기여했다.
shap_values = explainer.shap_values(X_test.iloc[:300])
shap.summary_plot(shap_values, X_train.iloc[:300])
shap.summary_plot(shap_values, X_train.iloc[:300], plot_type="violin")
shap.summary_plot(shap_values, X_train.iloc[:300], plot_type="bar")
'''
==> pumutation 보다 더 정확하다고 할 수 있다.
* pumutation features는 서로 다른 특성들간의 영향을 미치는 경우에는
결과가 정확하지 않을 수 있다
* 음의 관계에 대해서는 계산하지 않는다.
'''

= 하나의 관측치마다의 전체 변수의 중요도
= 그래프 상에서 특성은 예측에 미치는 영향력(=중요도)에 따라 정렬
= 현재 그래프로는 특성 값이 예측하는데 어떻게 영향을 준다고 판단하기는 어려움(ex. 작은값이 긍정, 큰 값이 부정과 같이 나눠져야 해석 가능)

= 전체 관측치에 대해서 전체 변수의 전박적인 중요도 값
shap_interaction_values = explainer.shap_interaction_values(X_train)
shap.summary_plot(shap_interaction_values, X_train)

- 각 특성 간의 관계(=상호작용 효과)를 파악
- 한 특성이 모델에 미치는 영향도에는 각 특성 간의 관계도 포함될 수 있어 이를 따로 분리함으로써 추가적인 인사이트 확인 가능
shap.dependence_plot(
('RM', 'LSTAT'),
shap_interaction_values, X_train,
display_features=X_train
)

# 클래스의 비율
y_train.value_counts(normalize=True)
'''
Fully Paid 0.847328
Charged Off 0.152672
Name: loan_status, dtype: float64
'''
ratio = 0.15/0.84
ratio
model = XGBClassifier(n_estimators=1000, verbosity=0,
n_jobs=-1,
scale_pos_weight=ratio)
서로 관련이 있는 모든 특성들에 대한 전역적인(Global) 설명
- Feature Importances
- Drop-Column Importances
- Permutaton Importances
타겟과 관련이 있는 개별 특성들에 대한 전역적인 설명
- Partial Dependence plots
개별 관측치에 대한 지역적인(local) 설명
- Shapley Values
'기계학습(ML) > Interpreting Model' 카테고리의 다른 글
n233 Feature Importances/ bagging, boosting (0) | 2021.06.26 |
---|---|
n232 Data Wrangling(랭글링) / merge / groupby (0) | 2021.06.26 |
n231 Choose your ML problems (0) | 2021.06.26 |
댓글