본문 바로가기

문돌이 존버/데이터 분석

(Explainable AI) SHAP 그래프 해석하기! feat. 실전 코드

반응형

이번 시간엔 파이썬 라이브러리로 구현된 SHAP을 직접 써보며 그 결과를 이해해보겠습니다. 보스턴 주택 데이터셋을 활용해보겠습니다.

import pandas as pd
import numpy as np

# xgb 모델 사용
from xgboost import XGBRegressor, plot_importance
from sklearn.model_selection import train_test_split

import shap

X, y = shap.datasets.boston()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=2021)

model = XGBRegressor()
model.fit(X_train, y_train)
shap.initjs()
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X_train)

먼저, force_plot 을 통해 특정 데이터 하나 또는 전체 데이터에 대해 Shapley value를 1차원 평면에 정렬해서 보여줍니다.

shap.force_plot(explainer.expected_value, shap_values[0, :], X_train.iloc[0, :])

집값 상승에 긍정적인 영향을 끼친 것은 빨간색으로 표시된 B, NOX고 막대 크기를 보면 NOX가 더 큰 영향을 준 듯 합니다. 반대로 부정적인 영향을 끼친 것은 파란색으로 표시된 RM, LSTAT 등이며 크기로 보면 RM(방의 수)이 가장 큰 영향을 끼쳤다고 할 수 있습니다.

전체 데이터에 대해서도 Shapley value를 누적하여 시각화할 수 있습니다. 

shap.initjs()
shap.force_plot(explainer.expected_value, shap_values, X_train)

x축이 각 데이터 관측치를 나타내며 마찬가지로 빨간색은 예측에 긍정적인 영향을, 파란색은 부정적인 영향을 끼칩니다. 그래프를 보면 왼쪽 부분은 집값을 낮추는, 오른쪽 부분은 집값을 올리는 요소들이 발견됨을 알 수 있습니다.

다음은 dependence_plot 을 통해 각 특성의 Shapely value를 확인할 수 있습니다.

shap.initjs()
# 총 13개 특성의 Shapley value를 절댓값 변환 후 각 특성마다 더함 -> np.argsort()는 작은 순서대로 정렬, 큰 순서대로 정렬하려면
# 앞에 마이너스(-) 기호를 붙임
top_inds = np.argsort(-np.sum(np.abs(shap_values), 0))

# 영향력 top 2 컬럼
for i in range(2):
    shap.dependence_plot(top_inds[i], shap_values, X_train)

x축은 특성(=컬럼) 값이고, y축은 해당 특성의 Shapley value를 가리킵니다. 오른쪽 y축에 나온 특성은 현재 그린 특성과의 관계(상호작용 효과)를 나타내는데, 그래프 상에서 색깔이 수직 패턴이 나오는 경우 관계가 존재한다고 합니다. 이와 관련해선 SHAP 라이브러리 예제 문서를 참고하시면 되겠습니다.

이제 summary_plot 에 대해 알아보겠습니다. 전체 특성들이 Shapley value 분포에 어떤 영향을 미치는지 시각화하는 것입니다.

shap.summary_plot(shap_values, X_train)

y축은 각 특성을, x축은 Shapely value를 나타내고 있습니다. 색깔은 특성값을 나타내어 빨간색으로 갈수록 높은 값을 의미합니다. 그래프 상에서 특성은 예측에 미치는 영향력(=중요도)에 따라 정렬됩니다. 즉 LSTAT가 결과값 예측에 가장 큰 영향을 끼치는 것입니다.

위 그래프를 보면, LSTAT 특성값이 작을수록(파란색) 예측에 긍정적인 영향을, 클수록(빨간색) 부정적인 영향을 미치고 있습니다.

똑같이 summary_plot을 사용하되 파라미터로 plot_type을 정해주면 각 특성이 모델에 미치는 절대 영향도(=기여분)를 눈으로 파악할 수 있습니다.

shap.summary_plot(shap_values, X_train, plot_type='bar')

마지막으로 interaction plot 에 대해 알아보겠습니다. 명칭에서 알 수 있듯이, 각 특성 간의 관계(=상호작용 효과)를 파악할 수 있습니다. 한 특성이 모델에 미치는 영향도에는 각 특성 간의 관계도 포함될 수 있어 이를 따로 분리함으로써 추가적인 인사이트를 발견할 수 있습니다.

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
)

참고로 게임 이론을 바탕으로 한 Shapley interaction value는 아래와 같이 정의됩니다.

특성 i와 j 간의 Shapley interaction value는 똑같은 크기의 2개 값으로 나뉩니다. 쉽게 말해, $\Phi_{i, j} = \Phi_{j, i}$를 말하며 총 Shapley interaction value는 이 2개를 더한 값($\Phi_{i, j} + \Phi_{j, i}$)이 됩니다.

그리고 모델 예측에 대한 한 특성의 주효과(main effect)는 Shapley value와 Shapley interaction value 간의 차이라고 정의할 수 있습니다.

$\Phi_{i, i} = \phi_i - \sum_{j \ne i} \Phi_{i, j}$


(참고)

Shapley value를 클러스터링(supervised clustering) 작업을 하는데도 사용할 수 있다고 합니다. 보통 특성들의 스케일은 동일하지 않고 차이가 납니다(예를 들어, 건물 높이 1층, 2층 vs 가격 100원, 1억). 하지만 Shaplely value는 모두 동일한 단위(모델 예측의 단위)를 가지고 있어 클러스터링 기법으로 사용하기 적절합니다. 즉 모든 관측치를 "영향력(=기여도)"에 따라 클러스터링을 진행합니다.

이는 위에서 소개했던 force_plot 에서 전체 데이터를 누적하여 시각화한 그래프를 보면 sample order by similarity 에 해당합니다. 아래는 논문에서 소개하고 있는 예시 그래프입니다.

Tree SHAP을 사용했으며, 각 관측치를 클러스터링 하는 데에는 "hierarchical agglomerative clustring" 기법을 사용했습니다. 빨간색 특성 기여분은 예측치에 긍정적인 영향을, 파란색 특성 기여분은 부정적인 영향을 끼쳤습니다.

참고
https://velog.io/@tobigs_xai/2%EC%A3%BC%EC%B0%A8-SHAP-SHapley-Additive-exPlanation
https://shap.readthedocs.io/en/latest/index.html
https://christophm.github.io/interpretable-ml-book/shap.html#treeshap
https://arxiv.org/pdf/1802.03888.pdf

 

728x90
반응형