Skip to content

ConceptCausalExplainer: Математическое обоснование

Обзор

ConceptCausalExplainer реализует новый подход к интерпретации моделей через каузальный анализ на уровне концептов, как описано в статье "Concept-Level Model Interpretation From the Causal Aspect". Вместо анализа важности отдельных признаков, этот модуль выявляет высокоуровневые концепты в данных и оценивает их каузальное влияние на поведение модели, предлагая интерпретируемость, которая соответствует понятным для человека концептам.

Математическая основа

Идентификация и извлечение концептов

Модуль использует двухэтапный подход к обнаружению концептов:

  1. Обнаружение концептов на основе кластеризации: Пространство данных разделяется с помощью кластеризации 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\) — другие концепты, выступающие в качестве контрольных переменных.

Применения

Этот подход предлагает несколько преимуществ:

  1. Интерпретируемость: Концепты соответствуют понятным для человека паттернам в данных
  2. Каузальное понимание: Оценки каузальных эффектов, а не корреляций
  3. Диагностическая сила: Выявляет, какие концепты каузально влияют на поведение модели
  4. Переносимость: Концепты могут применяться к разным моделям на одних и тех же данных

Понимая каузальные связи между концептами и поведением модели, пользователи могут принимать более обоснованные решения об улучшениях модели, сборе данных и стратегиях инжиниринга признаков.

Пример

examples/explainable/concept_explainer.py
"""
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()