Shapley Value와 SHAP에 대해서 간략한 설명과 실습 코드
Shapley Value와 SHAP(SHapley Additive exPlanations)
Shapley Value 와 SHAP는 이 데이터(분석단위)는 왜 그러한 결과로 예측 되었을까? 를 설명할 수 있는 방법 중 하나이다. 즉, 모델이 하나의 분석단위를 그렇게 예측한 이유에 대해 설명할 수 있다. 이는 실제 업무에서 사용자에게 설명할 수 있는 좋은 방법이라고 한다.
✅ Shapley Value
Shapley Value는 Feature의 가중 평균 기여도라고 할 수 있다.
예를 들어, A B C 라는 특성이 있을 때 A에 대한 Shapley Value를 계산하는 방법은 다음과 같다.
- A를 고정 시켜 놓고, 나머지 변수들로 조합을 구성한다.
즉, (A), (A, B), (A, C), (A, B, C) 총 4(=$2^2$)개 가 있다. - 이 각각의 조합에서 A를 포함했을 때의 예측 값과 A를 제외했을 때의 예측 값의 차이를 구한다.
ex) (A, B, C) 에서의 예측값 - (B, C) 에서의 예측 값 - 여기에 가중치를 곱해서, 각 조합의 기여도를 합친다.
이를 식으로 표현하면 아래와 같다.
\[\large \phi_i(f, x) = \sum_{z^\prime \subseteq x^\prime}{\frac{\vert z^\prime \vert (M - \vert z^\prime \vert - 1)!}{M!}} \cdot [ f_x(z^\prime ) - f_x ( z^\prime | i) ]\]
식을 뜯어보지말고, 대략적인 느낌으로만 이해해보자.
$\sum_{z^\prime \subseteq x^\prime}$ : 조합 하나씩 더하기
${\frac{\vert z^\prime \vert (M - \vert z^\prime \vert - 1)!}{M!}}$ : 가중치
$[f_x(z^\prime ) - f_x (z^\prime \vert i)]$ : 기여도
즉, 조합 별로 가중치 x 기여도의 값을 더한 것이 Shapley Value이다.
여기서 중요한 것은 예측 값에 대한 설명이라는 점이다. 실제 값과는 전혀 상관이 없다!
✅ SHAP(SHapely Additive exPlanation) 코드 실습
[SHAP 관련 코드]
파이썬에서 Shapley Value를 구하고, SHAP 분석을 시각화해보자. SHAP Explainer는 종류가 다양하게 있으며, 각 모델에 맞게 사용하면 된다.
[SHAP Explainers API Reference]
- 먼저 shap 라이브러리를 받자.
pip install shap
or conda install shap
. Colab에서 한다면 !pip install shap
을 실행하자. - 모델을 학습시키고, SHAP 값으로 모델의 예측을 설명하면 된다.
✔️ Shapley Value 구하기
1
2
3
4
5
6
7
| # 학습
rf_model = RandomForestRegressor()
rf_model.fit(x_train, y_train)
# 해석
explainer = shap.TreeExplainer(rf_model)
shap_values = explainer.shap_values(x_train)
|
- x_train과 shap_values의 크기는 동일하다.
- shap_values가 각 feature에 대한 기여도를 담고 있기 때문이다.
- Shapley Value의 행 별의 합 = $\hat{y}$ - 평균
1
2
| # 동일한 크기
x_train.shape, shap_values.shape
|
1
| pd.DataFrame(shap_values, columns=list(x))[:1]
|
| crim | zn | indus | chas | nox | rm | age | dis | rad | tax | ptratio | lstat |
---|
0 | 0.401934 | -0.006239 | -0.092199 | -0.014515 | 0.241373 | -2.366129 | 0.085752 | -0.365353 | -0.009492 | 0.343864 | 0.25944 | -0.504673 |
---|
| crim | zn | indus | chas | nox | rm | age | dis | rad | tax | ptratio | lstat |
---|
50 | 0.08873 | 21.0 | 5.64 | 0 | 0.439 | 5.963 | 45.7 | 6.8147 | 4 | 243 | 16.8 | 13.45 |
---|
1
2
| y_pred = rf_model.predict(x_train.iloc[:1, :])
y_pred[0]
|
1
| rf_model.predict(x_train).mean()
|
1
| y_pred[0] - rf_model.predict(x_train).mean()
|
1
| shap_values[:1, :].sum()
|
- 하나의 분석단위에 대한 Shapley Value 의 합 = 예측 값 - 예측 평균
- 랜덤 포레스트의 경우, 알고리즘의 특성상 약간의 차이가 발생 될 수 있다고 한다.
✔️ shap.force_plot
- 화살표의 길이 : Shapley Value, 기여도
- base value : 예측 값의 평균
1
2
3
4
5
| shap.initjs() # javascript 시각화 라이브러리 --> colab에서는 모든 셀에 포함시켜야 함
idx = 0
# force_plot(전체평균, shapley_values, input)
shap.force_plot(explainer.expected_value, shap_values[idx, :], x_train.iloc[idx,:])
|
✔️ shap.summary_plot
- 각 변수별 shapley value 분포를 한눈에 보여준다.
- 색깔은 해당 변수의 값의 크기를 나타낸다.
1
| shap.summary_plot(shap_values, x_train)
|
✔️ shap.force_plot
특정 관점으로 보기
1
2
| shap.initjs()
shap.force_plot(explainer.expected_value, shap_values, x_train)
|
✔️ shap.dependence_plot
- 특정 변수 값과 변수의 shap value 간의 관계 확인
1
| shap.dependence_plot('lstat', shap_values, x_train)
|
1
| shap.dependence_plot('lstat', shap_values, x_train, interaction_index = 'nox')
|