Глубина
~20 мин

Интерпретируемость моделей

SHAP, LIME, feature importance, partial dependence — как объяснить предсказания модели.

Интерпретируемость моделей — почему «оно работает» недостаточно

Банк отказал в кредите. Клиент спрашивает: «Почему?». По закону (GDPR статья 22, EU AI Act) банк обязан объяснить решение. Если за отказом стоит ML-модель, которая не может объяснить — модель юридически непригодна. Это не теория: в 2024 году EU AI Act вступил в силу, и модели высокого риска (кредитный скоринг, медицина, страхование) обязаны быть объяснимыми.

Но даже без регуляции — необъяснимая модель опасна. Ты не знаешь, на что она опирается. Может, она «выучила» артефакт в данных (ID пациента коррелирует с диагнозом), а не реальные паттерны. Без интерпретации ты не отладишь модель, не получишь trust от стейкхолдеров, не найдёшь баги.

Методы интерпретации ML-моделей: от feature importance до SHAP
Методы объяснения моделей: от простых (feature importance) до точных (SHAP)

Зачем объяснять модель

Три причины, по которым интерпретируемость — не опция, а необходимость:

  • Regulatory compliance. GDPR Article 22: право на объяснение автоматических решений. EU AI Act: модели высокого риска обязаны быть прозрачными. Пример: банк отказал в кредите → обязан объяснить, какие факторы повлияли.
  • Debugging. Модель может выучить ложные корреляции (shortcut learning). Пример: модель диагностики COVID научилась определять больничные бирки на рентгенах, а не патологию лёгких. Без интерпретации это не обнаружить.
  • Trust & buy-in. Бизнес-стейкхолдеры не развернут модель, которую не понимают. Data scientist объясняет модель продакт-менеджеру, тот — руководству. Пример: рекламный таргетинг — «почему этому пользователю показали эту рекламу?»

Feature Importance: быстро, но грубо

Impurity-based (встроенная в деревья)

Random Forest и Gradient Boosting имеют встроенный feature_importances_ — средний прирост чистоты (Gini impurity decrease) по всем деревьям. Плюсы: мгновенно, не требует дополнительных вычислений. Минусы: смещена в сторону high-cardinality фич (дата, ID), некорректна при коррелированных фичах (важность «размазывается» между ними). На практике часто врёт.

from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
import numpy as np

X, y = make_classification(n_samples=1000, n_features=10, random_state=42)
feature_names = [f'feat_{i}' for i in range(10)]

rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X, y)

# Impurity-based importance (встроенная, быстрая, но неточная)
importances = rf.feature_importances_
for name, imp in sorted(zip(feature_names, importances), key=lambda x: -x[1])[:5]:
    print(f"  {name}: {imp:.4f}")

Permutation Importance — более честный вариант

Идея: перемешиваем значения одной фичи случайным образом, измеряем падение метрики. Если фича важна — метрика сильно упадёт. Если не важна — метрика почти не изменится. Model-agnostic (работает с любой моделью), лучше обрабатывает корреляции. Минус: медленно — N_features * N_repeats вычислений модели.

from sklearn.inspection import permutation_importance

# Permutation importance — честнее, но медленнее
# ВАЖНО: считаем на TEST данных, не на train!
perm_imp = permutation_importance(
    rf, X_test, y_test,  # X_test, y_test — тестовая выборка
    n_repeats=10,
    random_state=42,
    scoring='f1'
)

for name, imp, std in sorted(
    zip(feature_names, perm_imp.importances_mean, perm_imp.importances_std),
    key=lambda x: -x[1]
)[:5]:
    print(f"  {name}: {imp:.4f} +/- {std:.4f}")

Permutation importance на тестовых данных

Permutation importance на тестовых данных — честная оценка. На тренировочных — переоценивает переобученные фичи (модель «запомнила» их, и перемешивание вызывает большое падение, даже если фича не несёт реальной информации).

SHAP — золотой стандарт объяснения

SHAP (SHapley Additive exPlanations) основан на значениях Шепли из теории игр. Каждая фича — «игрок», предсказание модели — «выигрыш». SHAP-значение фичи = средний маргинальный вклад этой фичи по всем возможным коалициям остальных фич. Математически строго, единственный метод, удовлетворяющий аксиомам эффективности, симметрии, линейности и dummy.

Shapley value: средний маргинальный вклад фичи i по всем подмножествам остальных фич

Три типа SHAP-графиков, которые должен знать каждый DS: (1) Summary plot — глобальная важность фич + направление влияния (красный = высокое значение фичи, синий = низкое). (2) Waterfall plot — объяснение одного предсказания: базовое значение + вклады каждой фичи = финальный скор. (3) Dependence plot — как одна фича влияет на предсказание с учётом взаимодействия с другой фичей.

import shap
import xgboost as xgb
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split

# Обучаем XGBoost
X, y = make_classification(n_samples=2000, n_features=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
feature_names = [f'feat_{i}' for i in range(10)]

model = xgb.XGBClassifier(n_estimators=100, max_depth=5, random_state=42)
model.fit(X_train, y_train)

# TreeExplainer — точный и быстрый для деревьев (XGBoost, LightGBM, RF)
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X_test)

# 1. Summary plot — глобальная важность + направление влияния
shap.summary_plot(shap_values, X_test, feature_names=feature_names, show=False)

# 2. Waterfall — объяснение одного предсказания
shap.plots.waterfall(explainer(X_test)[0], show=False)

# 3. Dependence plot — эффект одной фичи
shap.dependence_plot('feat_0', shap_values, X_test,
                     feature_names=feature_names, show=False)

SHAP для разных моделей: TreeSHAP — точный, O(TLD) для деревьев, за секунды на 100K объектов. KernelSHAP — для любой модели (нейросети, SVM), но медленный (sampling-based), минуты на 1K объектов. DeepSHAP — для нейросетей, gradient-based аппроксимация, быстрее KernelSHAP, но менее точный.

Выбирай метод по модели

TreeSHAP для бустинга — за секунды на 100K объектов. KernelSHAP для нейросетей — минуты на 1K. Выбирай SHAP-метод по типу модели, иначе будешь ждать часами.

LIME — объяснение одного предсказания

LIME (Local Interpretable Model-agnostic Explanations) объясняет одно конкретное предсказание. Как работает: возьми объект → сгенерируй возмущённые версии (перемешивая/маскируя фичи) → получи предсказания модели на них → обучи линейную модель на этих возмущениях → коэффициенты линейной модели = объяснение. Плюсы: работает с ЛЮБОЙ моделью (табулярные, текст, изображения). Минусы: нестабильный (разные perturbations → разные объяснения), медленный для batch.

import lime.lime_tabular
import numpy as np

# Создаём explainer
explainer = lime.lime_tabular.LimeTabularExplainer(
    training_data=X_train,
    feature_names=feature_names,
    class_names=['negative', 'positive'],
    mode='classification'
)

# Объяснение одного предсказания
explanation = explainer.explain_instance(
    X_test[0],                     # объект для объяснения
    model.predict_proba,           # функция предсказания
    num_features=5,                # топ-5 фич
    num_samples=1000               # сколько perturbations сгенерировать
)

# Топ-5 фич с вкладами
for feature, weight in explanation.as_list():
    print(f"  {feature}: {weight:+.4f}")

# Пример вывода:
# feat_2 > 0.47: +0.2134
# feat_5 <= -0.31: +0.1567
# feat_0 > 1.22: -0.0982

LIME vs SHAP: LIME быстрее для объяснения одного предсказания (не нужно считать Shapley по всем коалициям). SHAP теоретически обоснованнее (аксиомы Шепли гарантируют уникальность и справедливость). На практике для табулярных данных SHAP доминирует. LIME до сих пор полезен для текстов (какие слова повлияли на тональность?) и изображений (какие пиксели важны?).

Partial Dependence Plots (PDP)

PDP показывает маргинальный эффект одной фичи на предсказание, усреднённый по всем остальным фичам. Отвечает на вопрос: «Как изменится предсказание, если увеличить возраст клиента при прочих равных?». Отлично подходит для объяснения бизнесу — показывает монотонные/немонотонные зависимости.

from sklearn.inspection import PartialDependenceDisplay

# PDP для двух фич
fig, ax = plt.subplots(figsize=(12, 4))
PartialDependenceDisplay.from_estimator(
    model, X_test,
    features=[0, 3],           # индексы фич
    feature_names=feature_names,
    kind='both',               # 'both' = PDP + ICE линии
    ax=ax
)
# 'both' рисует:
# - PDP (синяя жирная линия) — средний эффект
# - ICE (серые тонкие линии) — индивидуальные эффекты

PDP предполагает независимость фич — если фичи коррелированы, PDP может показывать нереалистичные комбинации (например, высокий рост + низкий вес). ICE plots (Individual Conditional Expectation) частично решают эту проблему — показывают отдельную линию для каждого объекта вместо среднего. Если ICE-линии параллельны — эффект фичи одинаков для всех. Если расходятся — есть interaction effect.

На собесе

Junior

Что такое feature importance? Мера того, насколько каждая фича влияет на предсказания модели. Impurity-based (встроенная в деревья) или permutation (перемешиваем фичу, смотрим падение метрики). Почему нельзя объяснить модель одной accuracy? Accuracy говорит «насколько хорошо», но не «почему так». Без объяснения нельзя найти баги, получить доверие стейкхолдеров, соблюсти GDPR. Чем отличается global и local explanation? Global — какие фичи важны для модели в целом (summary plot, feature importance). Local — почему модель так предсказала для конкретного объекта (waterfall, LIME).

Middle

SHAP vs LIME: теория, скорость, стабильность? SHAP основан на значениях Шепли (теория игр, аксиоматически обоснован). LIME — локальная линейная аппроксимация (нестабильный, разные perturbations → разные ответы). SHAP теоретически строже, LIME быстрее для single prediction. Для табулярных данных SHAP доминирует. Impurity vs permutation importance: когда расходятся? При коррелированных фичах и high-cardinality. Impurity переоценивает кардинальные фичи (date, ID) и размазывает важность коррелированных. Permutation — честнее. Как объяснить предсказание бизнес-стейкхолдеру? Waterfall plot: «базовое значение + эти 5 факторов = финальное решение». Не показывай SHAP-формулы. Показывай «что повлияло» в терминах бизнеса: «доход клиента ниже порога — это снизило скор на 0.15».

Senior

Аксиомы Shapley: Эффективность (сумма SHAP = разница между предсказанием и baseline), Симметрия (одинаковые фичи получают одинаковый SHAP), Линейность (SHAP линейной комбинации моделей = линейная комбинация SHAP), Dummy (фича, не влияющая на предсказание, получает SHAP=0). SHAP для регулируемых индустрий (GDPR compliance): SHAP предоставляет attributions для каждого предсказания → соответствует требованиям GDPR Art.22 к объяснимости. Но SHAP — post-hoc метод, он объясняет модель, а не «правду» — объяснение может быть unfaithful. Limitations of post-hoc explanations: Post-hoc объяснения (SHAP, LIME) могут быть unfaithful — объяснение не отражает реальную логику модели. Пример: adversarial examples для SHAP (Slack et al., 2020). Альтернатива: inherently interpretable models — GAMs (Generalized Additive Models), EBMs (Explainable Boosting Machines), rule lists. EBM от Microsoft (InterpretML) даёт качество на уровне XGBoost при полной интерпретируемости.