๋ชฉํ
- PDP(Partial Dependence Plot; ๋ถ๋ถ์์กดํ๋) ์๊ฐํ ๋ฐ ํด์
- SHAP value plots๋ฅผ ์ฌ์ฉํด ๊ฐ๋ณ ์์ธก ์ฌ๋ก๋ฅผ ์ค๋ช
PDP(Partail Dependence Plots)
ํน์ ํน์ฑ์ ๋ํด ๊ทธ ๊ฐ์ ์ํ๋ค์ด ๊ฐ๊ณ ์๋ ๊ฐ๋ค๋ก ์ต์์์ ์ต๋๊น์ง ๋ฐ๊พธ์ด ๊ฐ๋ฉฐ ํ๊ฒ๊ฐ์ ์์ธกํด๋ณด๋ ๋ฐฉ๋ฒ์
๋๋ค.
train set์ ๋ํด ํ์ต๋ ๋ชจ๋ธ์ด ์์ด์ผํ๊ณ val ๋๋ test set์ ๋ํด์ PDP๋ฅผ ์งํํฉ๋๋ค.
๋๋คํฌ๋ ์คํธ, ๋ถ์คํ ๊ณผ ๊ฐ์ ์์๋ธ ๋ชจ๋ธ์ ๋์ ์ฑ๋ฅ์ ๊ฐ์ง์ง๋ง ์ ํ ๋ชจ๋ธ์ ๋นํด ํด์ํ๊ธฐ๊ฐ ์ด๋ ต์ต๋๋ค.
- ๋ณต์กํ ๋ชจ๋ธ : ์ดํดํ๊ธฐ ์ด๋ ต์ง๋ง ์ฑ๋ฅ์ด ์ฐ์
- ๋จ์ํ ๋ชจ๋ธ : ์ดํดํ๊ธฐ ์ฝ์ง๋ง ์ฑ๋ฅ์ด ๋ถ์กฑ
๋๋คํฌ๋ ์คํธ, ๋ถ์คํ
์ ๊ฒฝ์ฐ ์ฝ๊ฒ ํน์ฑ์ค์๋(feature importance)๋ฅผ ์ป์ ์ ์์ง๋ง ๋ ๋์๊ฐ ํน์ฑ์ ๊ฐ์ ๋ฐ๋ผ ํ๊ฒ๊ฐ์ ์ฆ๊ฐ์ฌ๋ถ ๋ฑ์ ํ์
ํ๊ธฐ๋ ์ด๋ ต์ต๋๋ค.(์ ํ ๋ชจ๋ธ์ ๊ฒฝ์ฐ, coefficients(ํ๊ท๊ณ์)๋ฅผ ์ด์ฉํด ๋ณ์์ ํ๊ฒ ๊ด๊ณ ํด์ ์ฉ์ด)
์ด ๋, PDP๋ฅผ ์ฌ์ฉํ๋ฉด ํน์ฑ์ด ํ๊ฒ์ ์ด๋ป๊ฒ ์ํฅ์ ์ฃผ๋์ง ๋น๊ต์ ์ฝ๊ฒ ํ์
ํ ์ ์์ต๋๋ค.
Tip) data set ๋๋ ๋, ๋ง์ง๋ง ์ํ์ ๊ธฐ์ค์ผ๋ก ๋๋๊ณ ์ถ์ ๋
test = df[-10000:] # ๋ง์ง๋ง ์ํ ์ ์ 10,000๊ฐ์ ์ํ
PDP-isolate(1๊ฐ์ ํน์ฑ ์ฌ์ฉ)
์์) ๋ถ์คํ ๋ชจ๋ธ์ ๋ํ ๊ฒฝ์ฐ
!pip install pdpbox
from pdpbox.pdp import pdp_isolate, pdp_plot
feature='A' # ์ํฅ์ ๋ณด๊ณ ์ถ์ ํน์ฑ
isolated = pdp_isolate(
model=boosting, # ์ฌ๊ธฐ์ ๋ชจ๋ธ์ ๊ธฐ์กด์ train set์ ๋ํด ํ์ต๋์ด์๋ ์ด๋ค ๋ชจ๋ธ ์
๋๋ค.
dataset=X_val,
model_features=X_val.columns,
feature=feature,
num_grid_points=10 # default=10
# grid point๋ฅผ ํฌ๊ฒ ์ฃผ๋ฉด ๊ฒน์น๋ ์ ์ด ์๊ฒจ number of unique grid points๋ ๋ ์ ์ ์ ์์ต๋๋ค.
)
pdp_plot(isolated, feature_name=feature);
ICE(Individual Conditional Expectation) curves
- ํ๋์ ICE curve๋ ํ๋์ ๊ด์ธก์น์ ๋ํด ๊ด์ฌ ํน์ฑ์ ๋ณํ์ํด์ ๋ฐ๋ฅธ ํ๊ฒ๊ฐ ๋ณํ ๊ณก์ ์ด๊ณ ์ด ICE๋ค์ ํ๊ท ์ด PDP์ ๋๋ค.
pdp_plot(isolated,
features_name=feature,
frac_to_plot=10, # ์ํ ์ : float์ผ๋ก ์ ์ผ๋ฉด, val set์ ์ x float / int๋ก ์ ์ผ๋ฉด ๊ทธ๋ฅ ๊ทธ ์ซ์๋งํผ์ data
plot_pts_dist=True # ๋งจ ์๋์ ์ํ๋ค์ ๋ถํฌ๋ฅผ ๋ณผ ์ ์๋ ๋ฐ์ฝ๋ ๊ฐ์ด ์๊ธด plot ์ ๋ฌด
)
grid point๋ก plot๋๋ ๊ณผ์
PDP-interact(2๊ฐ์ ํน์ฑ ์ฌ์ฉ)
- ๋ ํน์ฑ๊ฐ์ ์ํธ์์ฉ์ PDP๋ฅผ ํตํด ํ์ธ ๊ฐ๋ฅ
from pdpbox.pdp import pdp_interact, pdp_interact_plot
features = ['A', 'B']
interaction = pdp_interact(
model=boosting,
dataset=X_val,
model_features=X_val.columns,
features=features
)
pdp_interact_plot(interaction, plot_type='grid', feature_names=features);
Plotly๋ฅผ ํ์ฉํ์ฌ PDP-interaction์ 3D๋ก ๋ณด์ฌ์ค ์ ์์ต๋๋ค.
pdp = interaction.pdp.pivot_table(
values='preds', # interaction['preds']
columns=features[0],
index=features[1]
) # [::-1] index๋ฅผ ์ญ์์ผ๋ก ๋ง๋๋ sclicing์ผ๋ก ๋ ํน์ฑ ๊ฐ์ ํ๊ฒ๊ฐ๊ณผ์ ๊ด๊ณ๋ฅผ ์ ๋ฐ์ ธ์ ๋ฐฉํฅ์ ๋ง๊ฒ ์ ์ฉ
import plotly.graph_objs as go
surface = go.Surface(
x=pdp.columns,
y=pdp.index,
z=pdp.values
)
layout = go.Layout(
scene=dict(
xaxis=dict(title=features[0]),
yaxis=dict(title=features[1]),
zaxis=dict(title=target)
)
)
fig = go.Figure(surface, layout)
fig.show()
SHAP
- ๋จ์ผ ๊ด์ธก์น๋ก๋ถํฐ ํน์ฑ๋ค์ ๊ธฐ์ฌ๋(feature attribution)๋ฅผ ๊ณ์ฐํ๊ธฐ ์ํ ๋ฐฉ๋ฒ
- ์ด๋ค ๋จธ์ ๋ฌ๋ ๋ชจ๋ธ์ด๋ ์ง ์ ์ฉ ๊ฐ๋ฅ
- Shapley value๋ ์๋ ๊ฒ์์ด๋ก ์์ ๋์ค๋ ๊ฐ๋ ์ผ๋ก ๋ณต์กํ ๋จธ์ ๋ฌ๋๋ชจ๋ธ์ ์์ธก์ ์ค๋ช ํ๊ธฐ ์ข์ ๋ฐฉ๋ฒ์ ์ ๊ณต
Shapley values
- ๊ฒ์์ด๋ก ์์ ๊ฐ์ ํ ์ ์๋ค(ํน์ฑ๋ค)์ด ๊ฒ์ ๋ชฉํ(ํ๊ฒ, ์์ธก๊ฐ) ๋ฌ์ฑ์ ์ํด ๊ฐ์ ์์ ์ ์ญํ (๊ธฐ์ฌ๋)์ ํ๋ค๊ณ
ํ ๋, ๋ชฉํ ๋ฌ์ฑ ํ ๋ฐ์ ํฌ์์ ์ด๋ป๊ฒ ํ๋ฉด ๊ธฐ์ฌ๋์ ๋ฐ๋ผ ๊ณตํํ๊ฒ ๋๋ ์ ์์๊น? ์ ๊ด๋ จ๋ฉ๋๋ค.
row = X_test.iloc[[1]] # ์ค์ฒฉ brackets์ ์ฌ์ฉํ๋ฉด ๊ฒฐ๊ณผ๋ฌผ์ด DataFrame์
๋๋ค
row # ๊ด์ธก์น ํ๋๋ฅผ ์ ํ
# ์ค์ ์ง๊ฐ ํ์ธ
y_test.iloc[[1]] # 2๋ฒ์งธ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ์ต๋๋ค
# ๋ชจ๋ธ ์์ธก๊ฐ ํ์ธ
model.predict(row)
!pip install shap
# ๋ชจ๋ธ์ด ์ด๋ ๊ฒ ์์ธกํ ์ด์ ๋ฅผ ์๊ธฐ ์ํ์ฌ
# SHAP Force Plot์ ๊ทธ๋ ค๋ณด๊ฒ ์ต๋๋ค.
import shap
explainer = shap.TreeExplainer(model) # ํธ๋ฆฌ๋ชจ๋ธ์ ๋ํด ์ค๋ช
ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
shap_values = explainer.shap_values(row)
shap.initjs() # javascript ์ด๊ธฐํ (graph ์ด๊ธฐํ) ๊ฐ ์
๋ง๋ค ์จ์ฃผ์ด์ผ plot์ด ์ ๋ณด์
๋๋ค.
shap.force_plot( # ์ ๋ง ๋ง๊ทธ๋๋ก force(ํ)์ ๋ณด๋ ๊ฒ, ์์ ํ/์์ ํ ๋น๊ต
base_value=explainer.expected_value,
shap_values=shap_values,
features=row
)
์ฆ, ์ด ์ํ์ ๋ํด์ ๊ฐ๊ฐ์ ํน์ฑ๊ณผ ๊ทธ ํน์ฑ์ด ์์ธกํ ํ๊ฒ๊ฐ์ด base value(train set์ ๋ํ ํ๊ฒ ์์ธก๊ฐ๋ค์ ํ๊ท )์ผ๋ก๋ถํฐ ์ด๋ป๊ฒ ํด์ ๋์ค๊ฒ ๋์๋์ง๋ฅผ ๋ณด์ฌ์ค๋๋ค.
์ฃผ์) ์์ ๊ฒฐ๊ณผ์์ 'bathrooms๋ ํ๊ฒ๊ณผ ์์ ๊ด๊ณ์ ์๋ค.'๋ผ๊ณ ํด์ํ๋ฉด ์๋ฉ๋๋ค. ๊ทธ์ ์ด ์ํ์์๋ 'bathrooms=2.5'๋ผ๋ ๊ฒ ์์ ์ญํ ์ ํ๋ค๊ณ ์๊ฐํ๋ฉด ๋ฉ๋๋ค.
์์ ๊ฒฝ์ฐ๋ฅผ ํ๋์ row๊ฐ ์๋ ์ฌ๋ฌ๊ฐ์ row์ ๋ํด ๋์์ ํ๋ฉด ์๋์ ๊ฐ์ต๋๋ค.
# 100๊ฐ ํ
์คํธ ์ํ์ ๋ํด์ ๊ฐ ํน์ฑ๋ค์ ์ํฅ์ ๋ด
๋๋ค. ์ํ ์๋ฅผ ๋๋ฌด ํฌ๊ฒ ์ข์ผ๋ฉด ๊ณ์ฐ์ด ์ค๋๊ฑธ๋ฆฌ๋ ์ฃผ์ํ์ธ์.
shap.initjs()
shap_values = explainer.shap_values(X_test.iloc[:100])
shap.force_plot(explainer.expected_value, shap_values, features=X_test.iloc[:100])
- x์ถ๊ณผ y์ถ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
์ถ๊ฐ ํ(์ฐธ๊ณ ๋ง)
def predict(bedrooms, bathrooms, longitude, latitude):
# ํจ์ ๋ด์์ ์์ธก์ ์ฌ์ฉ๋ input์ ๋ง๋ญ๋๋ค
df = pd.DataFrame(
data=[[bedrooms, bathrooms, longitude, latitude]],
columns=['bedrooms', 'bathrooms', 'long', 'lat']
)
# ์์ธก
pred = model.predict(df)[0]
# Shap value๋ฅผ ๊ณ์ฐํฉ๋๋ค
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(df)
# Shap value, ํน์ฑ์ด๋ฆ, ํน์ฑ๊ฐ์ ๊ฐ์ง๋ Series๋ฅผ ๋ง๋ญ๋๋ค
feature_names = df.columns
feature_values = df.values[0]
shaps = pd.Series(shap_values[0], zip(feature_names, feature_values))
# ๊ฒฐ๊ณผ๋ฅผ ํ๋ฆฐํธ ํฉ๋๋ค.
result = f'ํ๊ท ๊ฐ๊ฒฉ: ${explainer.expected_value[0]:,.0f} \n'
result += f'์์ธก๊ฐ๊ฒฉ: ${pred:,.0f}. \n'
result += shaps.to_string()
print(result)
# SHAP Force Plot
shap.initjs()
return shap.force_plot(
base_value=explainer.expected_value,
shap_values=shap_values,
features=df
)
์์ ๊ฐ์ด predict ํจ์๋ฅผ ์ ์ํ๋ฉด
์ ๊ฐ์ด ๊ฐ์ ๋์ ํด์ ์์ธก๊ฐ ๋ฐ ๊ฐ ํน์ฑ๊ฐ์ ๋ํ ๊ธฐ์ฌ๋๋ฅผ ๊ฐ๋จํ๊ฒ ๋ณผ ์ ์์ต๋๋ค.
summary_plot
shap_values = explainer.shap_values(X_test.iloc[:300])
shap.summary_plot(shap_values, X_test.iloc[:300])
shap.summary_plot(shap_values, X_test.iloc[:300], plot_type="violin")
shap.summary_plot(shap_values, X_test.iloc[:300], plot_type="bar")
- ์ผํ ๋ณด๋ฉด feature importance(MDI)์ ๋น์ทํ์ง๋ง ๋ถ์๋๋ฅผ ๋ฐ์ง๋ ๊ฒ์ด ์๋ ๊ฐ ํน์ฑ๋ค์ ๊ฐ์ด ๊ฐ๋ Shapley value๋ค์ ์ ๋๊ฐ ํ๊ท ์ ๋ํ๋ ๋๋ค.
์ถ๊ฐ) ๋ถ๋ฅ๋ฌธ์ ์์์ SHAP ํ์ฉ
import xgboost
import shap
explainer = shap.TreeExplainer(model)
row_processed = processor.transform(row)
shap_values = explainer.shap_values(row_processed)
shap.initjs()
shap.force_plot(
base_value=explainer.expected_value,
shap_values=shap_values,
features=row,
link='logit' # SHAP value๋ฅผ ํ๋ฅ ๋ก ๋ณํํด ํ์ํฉ๋๋ค. ์ด ๋ถ๋ถ์ ๊ธฐ์ต
)
'๐ฟ Data > ๋ถํธ์บ ํ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[TIL]45_Section2_Review(2) (0) | 2022.01.15 |
---|---|
[TIL]37_Section2_sprint3_challenge (0) | 2022.01.06 |
[TIL]35.Feature Importance (0) | 2022.01.04 |
[TIL]34.Data Wrangling (0) | 2022.01.03 |
[TIL]33.Choose your ML problems (0) | 2022.01.01 |