ConceptCausalExplainer: Математическое обоснование¶
Обзор¶
ConceptCausalExplainer
реализует новый подход к
интерпретации моделей через каузальный анализ на уровне концептов,
как описано в статье
"Concept-Level Model Interpretation From the Causal Aspect".
Вместо анализа важности отдельных признаков, этот модуль выявляет высокоуровневые концепты
в данных и оценивает их каузальное влияние на поведение модели,
предлагая интерпретируемость, которая соответствует понятным для человека концептам.
Математическая основа¶
Идентификация и извлечение концептов¶
Модуль использует двухэтапный подход к обнаружению концептов:
- Обнаружение концептов на основе кластеризации: Пространство данных разделяется с помощью кластеризации KMeans:
\( C_i = \{x_j \in D \mid \arg\min_k \|x_j - \mu_k\|^2 = i\} \)
где:
- \(C_i\) представляет кластер \(i\),
- \(D\) — это набор данных для обнаружения,
- \(\mu_k\) — это центроиды кластеров.
2. Дискриминационная валидация концептов: Каждый кластер валидируется путем обучения линейного SVM:
\( S_i(x) = \text{sign}(w_i^T x + b_i) \)
Кластер считается валидным концептом, если его можно отличить от естественного набора данных с AUC > порога.
Представление в пространстве концептов¶
Пространство признаков преобразуется в пространство концептов: \( A(x) = [A_1(x), A_2(x), ..., A_m(x)] \) где \(A_i(x) = 1\), если \(x\) принадлежит концепту \(i\), и 0 в противном случае.
Оценка каузального эффекта¶
Для бинарного исхода \(L_f\) каузальный эффект концепта \(A_i\) оценивается с помощью: \(\tau_i = \mathbb{E}[L_f \mid do(A_i = 1)] - \mathbb{E}[L_f \mid do(A_i = 0)]\)
Для непрерывных исходов, таких как уверенность модели, используется фреймворк Double Machine Learning: \(\tau_i(x) = \mathbb{E}[Y \mid do(A_i = 1), X = x] - \mathbb{E}[Y \mid do(A_i = 0), X = x]\)
где \(Y\) — интересующий исход (например, уверенность модели), а \(X\) — другие концепты, выступающие в качестве контрольных переменных.
Применения¶
Этот подход предлагает несколько преимуществ:
- Интерпретируемость: Концепты соответствуют понятным для человека паттернам в данных
- Каузальное понимание: Оценки каузальных эффектов, а не корреляций
- Диагностическая сила: Выявляет, какие концепты каузально влияют на поведение модели
- Переносимость: Концепты могут применяться к разным моделям на одних и тех же данных
Понимая каузальные связи между концептами и поведением модели, пользователи могут принимать более обоснованные решения об улучшениях модели, сборе данных и стратегиях инжиниринга признаков.
Пример¶
"""
Example usage script for the CausalModelExplainer class defined in causal_explanator.py.
This script demonstrates how to:
1. Load and preprocess the UCI Adult dataset (as an example).
2. Create and configure the CausalModelExplainer.
3. Extract concepts, generate a concept space, train a predictive model, and estimate causal effects.
Run this script to see how the methods can be chained together for end-to-end analysis.
"""
import pandas as pd
from rich import print as rprint
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from applybn.explainable.causal_analysis import ConceptCausalExplainer
def load_and_preprocess_data():
"""Load and preprocess the UCI Adult dataset.
Returns:
tuple: (X_processed, y, X_original) where:
X_processed (pd.DataFrame): Processed features, ready for modeling.
y (pd.Series): Binary labels (income >50K or <=50K).
X_original (pd.DataFrame): Original features before encoding/scaling.
"""
url = "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data"
column_names = [
"age",
"workclass",
"fnlwgt",
"education",
"education-num",
"marital-status",
"occupation",
"relationship",
"race",
"sex",
"capital-gain",
"capital-loss",
"hours-per-week",
"native-country",
"income",
]
data = pd.read_csv(url, names=column_names, header=None, na_values=" ?")
data.dropna(inplace=True)
data.reset_index(drop=True, inplace=True)
X_original = data.drop("income", axis=1).reset_index(drop=True)
y = (
data["income"]
.apply(lambda x: 1 if x.strip() == ">50K" else 0)
.reset_index(drop=True)
)
# One-hot encode categorical columns
categorical_cols = X_original.select_dtypes(include=["object"]).columns
encoder = OneHotEncoder(sparse_output=False, handle_unknown="ignore")
X_encoded = pd.DataFrame(
encoder.fit_transform(X_original[categorical_cols]),
columns=encoder.get_feature_names_out(categorical_cols),
)
X_numeric = X_original.select_dtypes(exclude=["object"]).reset_index(drop=True)
X_processed = pd.concat(
[X_numeric.reset_index(drop=True), X_encoded.reset_index(drop=True)], axis=1
)
# Scale numeric columns
numeric_cols = X_numeric.columns
scaler = StandardScaler()
X_processed[numeric_cols] = scaler.fit_transform(X_processed[numeric_cols])
X_processed.reset_index(drop=True, inplace=True)
return X_processed, y, X_original
def main():
"""Demonstration of using CausalModelExplainer on a sample dataset."""
# Load and preprocess data
X, y, original_X = load_and_preprocess_data()
# Create discovery (D) and natural (N) datasets
D, N = train_test_split(X, test_size=0.3, random_state=42, shuffle=False)
D.reset_index(drop=False, inplace=True)
N.reset_index(drop=False, inplace=True)
# Instantiate the explainer
explainer = ConceptCausalExplainer()
# Extract concepts
cluster_concepts = explainer.extract_concepts(D, N)
# Generate concept space
A = explainer.generate_concept_space(X, cluster_concepts)
# Train a random forest classifier for demonstration
predictive_model = RandomForestClassifier(n_estimators=100, random_state=42)
predictive_model.fit(X, y)
# Calculate confidence and uncertainty
confidence, uncertainty = explainer.calculate_confidence_uncertainty(
X, y, predictive_model
)
# Prepare data for causal effect estimation
D_c_confidence = A.copy()
D_c_confidence["confidence"] = confidence
D_c_uncertainty = A.copy()
D_c_uncertainty["uncertainty"] = uncertainty
# Estimate causal effects
effects_confidence = explainer.estimate_causal_effects_on_continuous_outcomes(
D_c_confidence, outcome_name="confidence"
)
effects_uncertainty = explainer.estimate_causal_effects_on_continuous_outcomes(
D_c_uncertainty, outcome_name="uncertainty"
)
# Generate visualizations
explainer.plot_tornado(
effects_confidence, title="Causal Effects on Model Confidence", figsize=(10, 8)
)
explainer.plot_tornado(
effects_uncertainty,
title="Causal Effects on Model Uncertainty",
figsize=(10, 8),
)
# Extract and log concept meanings
selected_features_per_concept = explainer.extract_concept_meanings(
D, cluster_concepts, original_X
)
rprint(f"\nConcept feature details: {selected_features_per_concept}")
if __name__ == "__main__":
main()