086 모델 해석 - Partial Dependence
키워드: Partial Dependence, PDP
개요
Partial Dependence Plot(PDP)은 특정 특성이 모델 예측에 미치는 영향을 시각화하는 기법입니다. 다른 특성을 평균화하여 관심 특성과 예측 간의 관계를 보여줍니다.
실습 환경
- Python 버전: 3.11 권장
- 필요 패키지:
pycaret[full]>=3.0
Partial Dependence란?
Partial Dependence:
"특성 X가 변할 때 예측 Y는 어떻게 변하는가?"
계산 방법:
1. 특성 X의 값을 고정
2. 다른 모든 특성은 실제 데이터 값 사용
3. 예측값의 평균 계산
4. X 값을 바꿔가며 반복
결과:
- X축: 특성 값
- Y축: 평균 예측값 (또는 확률)
PyCaret에서 PDP
from pycaret.classification import *
from pycaret.datasets import get_data
# 086 데이터 로드
data = get_data('diabetes')
# 086 환경 설정
clf = setup(data, target='Class variable', session_id=42, verbose=False)
# 086 모델 생성
rf = create_model('rf')
# 086 Partial Dependence Plot
interpret_model(rf, plot='pdp')
sklearn에서 직접 사용
from sklearn.ensemble import RandomForestClassifier
from sklearn.inspection import PartialDependenceDisplay
import matplotlib.pyplot as plt
from pycaret.datasets import get_data
# 086 데이터 준비
data = get_data('diabetes')
X = data.drop('Class variable', axis=1)
y = data['Class variable']
# 086 모델 학습
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X, y)
# 086 단일 특성 PDP
fig, ax = plt.subplots(figsize=(10, 6))
PartialDependenceDisplay.from_estimator(
rf, X,
features=['BMI'], # 분석할 특성
ax=ax
)
plt.title('Partial Dependence: BMI')
plt.savefig('pdp_single.png', dpi=150)
여러 특성 PDP
from sklearn.inspection import PartialDependenceDisplay
import matplotlib.pyplot as plt
# 086 여러 특성 한 번에
features_to_plot = ['BMI', 'Age', 'DiabetesPedigreeFunction', 'Glucose']
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes = axes.flatten()
for ax, feature in zip(axes, features_to_plot):
PartialDependenceDisplay.from_estimator(
rf, X,
features=[feature],
ax=ax
)
ax.set_title(f'PDP: {feature}')
plt.tight_layout()
plt.savefig('pdp_multiple.png', dpi=150)
2D PDP (상호작용)
from sklearn.inspection import PartialDependenceDisplay
import matplotlib.pyplot as plt
# 086 두 특성 간 상호작용
fig, ax = plt.subplots(figsize=(10, 8))
PartialDependenceDisplay.from_estimator(
rf, X,
features=[('BMI', 'Age')], # 2D: 튜플로 지정
ax=ax,
kind='both' # 등고선 + 3D
)
plt.title('2D PDP: BMI vs Age')
plt.savefig('pdp_2d.png', dpi=150)
ICE Plot (Individual Conditional Expectation)
from sklearn.inspection import PartialDependenceDisplay
import matplotlib.pyplot as plt
# 086 ICE: 개별 관측치별 조건부 기대값
fig, ax = plt.subplots(figsize=(10, 6))
PartialDependenceDisplay.from_estimator(
rf, X,
features=['BMI'],
kind='both', # PDP + ICE
ax=ax,
ice_lines_kw={'alpha': 0.1, 'color': 'gray'}, # ICE 선 스타일
pd_line_kw={'color': 'red', 'linewidth': 3} # PDP 선 스타일
)
plt.title('ICE Plot + PDP: BMI')
plt.savefig('ice_plot.png', dpi=150)
PDP vs ICE
PDP (Partial Dependence):
- 평균적인 영향
- 하나의 선
- 전체 경향 파악
ICE (Individual Conditional Expectation):
- 개별 관측치별 영향
- 여러 선
- 이질성(heterogeneity) 파악
- 상호작용 효과 발견
해석 예시
from sklearn.inspection import PartialDependenceDisplay
import matplotlib.pyplot as plt
import numpy as np
# 086 BMI에 대한 상세 분석
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
# 1. PDP만
PartialDependenceDisplay.from_estimator(
rf, X, features=['BMI'], ax=axes[0], kind='average'
)
axes[0].set_title('PDP Only')
# 2. ICE만
PartialDependenceDisplay.from_estimator(
rf, X, features=['BMI'], ax=axes[1], kind='individual',
ice_lines_kw={'alpha': 0.3}
)
axes[1].set_title('ICE Only')
# 3. PDP + ICE
PartialDependenceDisplay.from_estimator(
rf, X, features=['BMI'], ax=axes[2], kind='both',
ice_lines_kw={'alpha': 0.1},
pd_line_kw={'color': 'red', 'linewidth': 3}
)
axes[2].set_title('PDP + ICE')
plt.tight_layout()
plt.savefig('pdp_ice_comparison.png', dpi=150)
해석 가이드
PDP 해석:
선형 증가:
↗️ 특성 증가 → 예측 증가
선형 감소:
↘️ 특성 증가 → 예측 감소
비선형:
⤴️ 임계값 이후 급격히 변화
평탄:
➡️ 특성이 예측에 영향 없음
U자형:
∪ 양 극단에서 예측 증가
역U자형:
∩ 중간 값에서 최대
회귀 문제에서 PDP
from pycaret.regression import *
from pycaret.datasets import get_data
# 086 회귀 데이터
data = get_data('boston')
# 086 환경 설정
reg = setup(data, target='medv', session_id=42, verbose=False)
# 086 모델 생성
rf = create_model('rf')
# 086 PDP
interpret_model(rf, plot='pdp')
직접 계산 (이해를 위해)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
def manual_pdp(model, X, feature, grid_resolution=50):
"""PDP 수동 계산"""
# 특성 범위
feature_values = np.linspace(
X[feature].min(),
X[feature].max(),
grid_resolution
)
# 각 값에 대해 예측 평균 계산
avg_predictions = []
for val in feature_values:
# 모든 데이터에 대해 해당 특성 값을 고정
X_modified = X.copy()
X_modified[feature] = val
# 예측 (확률)
if hasattr(model, 'predict_proba'):
preds = model.predict_proba(X_modified)[:, 1]
else:
preds = model.predict(X_modified)
avg_predictions.append(preds.mean())
return feature_values, avg_predictions
# 086 사용 예
feature_values, avg_preds = manual_pdp(rf, X, 'BMI')
plt.figure(figsize=(10, 6))
plt.plot(feature_values, avg_preds, 'b-', linewidth=2)
plt.xlabel('BMI')
plt.ylabel('Average Predicted Probability')
plt.title('Manual PDP: BMI')
plt.grid(True, alpha=0.3)
plt.savefig('manual_pdp.png', dpi=150)
PDP 주의사항
주의사항:
1. 특성 상관관계
- 상관된 특성이 있으면 해석 왜곡
- 불가능한 특성 조합 고려됨
- ALE Plot이 대안
2. 평균의 함정
- 이질적인 효과가 상쇄될 수 있음
- ICE Plot으로 확인
3. 외삽(Extrapolation)
- 데이터 범위 밖의 해석 주의
- 데이터가 희소한 영역 주의
4. 계산 비용
- 모든 데이터 × 그리드 포인트
- 대용량에서 샘플링 필요
ALE Plot (대안)
# 086 pip install alibi
try:
from alibi.explainers import ALE, plot_ale
import matplotlib.pyplot as plt
# ALE (Accumulated Local Effects)
# 상관된 특성에서 PDP보다 신뢰성 높음
ale = ALE(rf.predict_proba, feature_names=X.columns.tolist())
ale_explanation = ale.explain(X.values)
# 시각화
plot_ale(ale_explanation, features=['BMI'])
plt.savefig('ale_plot.png', dpi=150)
except ImportError:
print("alibi 패키지 필요: pip install alibi")
정리
- PDP: 특성이 예측에 미치는 평균 효과
- ICE: 개별 관측치별 효과 (이질성 확인)
- 2D PDP: 두 특성 간 상호작용
- 상관된 특성에서는 ALE 고려
- 해석 시 데이터 분포 함께 확인
다음 글 예고
다음 글에서는 자동 특성 선택을 다룹니다.
PyCaret 머신러닝 마스터 시리즈 #086