A complete implementation of necessity and sufficiency metrics for evaluating the robustness of explainable AI (XAI) methods, specifically LIME and SHAP, on tabular data.
This repository implements the methodologies from two key papers:
-
Chowdhury et al. (2023) - "Explaining Explainers: Necessity and Sufficiency in Tabular Data"
- NeurIPS 2023 Workshop on Table Representation Learning
-
Chowdhury et al. (2025) - "A unified framework for evaluating the robustness of machine-learning interpretability for prospect risking"
- Geophysics, Vol. 90, No. 3
This framework provides:
- Necessity Scores: Quantifies how essential each feature is for a model's prediction
- Sufficiency Scores: Quantifies how much a feature alone can drive predictions
- Robustness Analysis: Evaluates whether LIME and SHAP explanations align with necessity/sufficiency
- Forward Counterfactuals: Generates counterfactuals without requiring target predictions
"If I change this feature, will the model's prediction change?"
A feature has high necessity if altering its value consistently flips the model's decision. Mathematically:
Necessity(x_j) = P(y ≠ y* | x_j ← a')
Where:
x_jis the feature being evaluatedy*is the original predictiona'is a perturbed value
"If I set this feature to a specific value, can it guarantee a certain prediction?"
A feature has high sufficiency if setting it to a target value reliably produces the desired outcome:
Sufficiency(x_j) = P(y = y* | x_j ← a)
An important feature should be both necessary AND sufficient.
If LIME or SHAP ranks a feature as highly important, we expect:
- Its necessity score to be high (changing it affects predictions)
- Its sufficiency score to be high (it can drive predictions)
The framework calculates global scores for each feature by aggregating local counterfactual interventions:
The framework evaluates whether top-ranked features by LIME/SHAP are truly necessary and sufficient:
Ideal Robustness: Scores should decrease monotonically with rank (Rank 1 > Rank 2 > Rank 3...)
# Clone the repository
git clone https://github.com/yourusername/necessity-sufficiency-xai.git
cd necessity-sufficiency-xai
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txtRun analysis on the Breast Cancer dataset with Logistic Regression:
cd src
python main.py --dataset breast_cancer --model logisticRun with different configurations:
# Random Forest on Breast Cancer
python main.py --dataset breast_cancer --model random_forest
# Gaussian Naive Bayes on Iris
python main.py --dataset iris --model gaussian_nb
# Custom parameters
python main.py --dataset breast_cancer --model logistic \
--n_samples 200 --top_k 7 --output_dir ../my_results| Argument | Default | Description |
|---|---|---|
--dataset |
breast_cancer |
Dataset to use: breast_cancer, iris |
--model |
logistic |
Model type: logistic, random_forest, gaussian_nb |
--n_samples |
100 |
Number of samples for global score calculation |
--top_k |
5 |
Number of top features for robustness analysis |
--output_dir |
results |
Directory to save results |
necessity-sufficiency-xai/
├── src/
│ ├── main.py # Main analysis script
│ ├── counterfactual_generator.py # Forward CF generation
│ ├── xai_evaluator.py # LIME/SHAP robustness evaluation
│ └── visualization.py # Plotting utilities
├── notebooks/
│ ├── 01_introduction.ipynb # Introduction and concepts
│ ├── 02_toy_example.ipynb # Validation with logical operators
│ └── 03_full_analysis.ipynb # Complete analysis walkthrough
├── data/
│ └── README.md # Data description
├── results/
│ └── (generated outputs) # Analysis results
├── images/
│ └── (figures and diagrams) # Documentation images
├── docs/
│ ├── methodology.md # Detailed methodology
│ └── api_reference.md # API documentation
├── requirements.txt # Python dependencies
└── README.md # This file
Unlike traditional counterfactual methods (e.g., DiCE) that optimize towards a target prediction, our forward approach:
# Traditional CF: Find x' such that f(x') = target_y
# Forward CF: Perturb x_j and observe f(x')
# For necessity
for instance in dataset:
for feature in features:
perturb_feature(instance, feature)
if prediction_changed():
necessity_score += 1Advantages:
- No need for target predictions
- Works on sparse, high-dimensional data
- No causal model required
- Computationally efficient
Global scores aggregate local counterfactual results:
Global_Necessity(x_j) = (1/N) Σ Local_Necessity(x_j, instance_i)Where N is the number of sampled instances.
For each test instance:
- Get LIME/SHAP feature rankings
- Map rankings to global necessity/sufficiency scores
- Evaluate if scores decrease monotonically with rank
The framework is validated using synthetic data with known logical relationships:
Y = X2 AND X3 # Output is 1 only if both inputs are 1
Expected:
- Necessity = 100% (changing either input changes output)
- Sufficiency = 33.3% (both must be 1 for output 1)Y = X2 OR X3 # Output is 1 if either input is 1
Expected:
- Necessity = 33.3% (only matters when both are 0)
- Sufficiency = 66.7% (either input can produce output)See notebooks/02_toy_example.ipynb for complete validation.
High Necessity + High Sufficiency
- Feature is crucial for model decisions
- Strong causal relationship
- Should be top-ranked by XAI methods
High Necessity + Low Sufficiency
- Feature is important but not alone sufficient
- Part of feature interactions
- May require other features
Low Necessity + High Sufficiency
- Feature can drive decisions but isn't always needed
- Model may have alternative decision paths
- Could indicate redundancy
Low Necessity + Low Sufficiency
- Feature is not important for model
- Should not be top-ranked by XAI methods
Robust Explanation (Ideal):
Rank 1: 0.85 ← Highest
Rank 2: 0.72
Rank 3: 0.58
Rank 4: 0.43
Rank 5: 0.31 ← Lowest
Non-Robust Explanation:
Rank 1: 0.45 ← Not highest!
Rank 2: 0.78 ← Higher than Rank 1
Rank 3: 0.52
Rank 4: 0.61 ← Non-monotonic
Rank 5: 0.35
If you use this code in your research, please cite:
@inproceedings{chowdhury2023explaining,
title={Explaining Explainers: Necessity and Sufficiency in Tabular Data},
author={Chowdhury, Prithwijit and Prabhushankar, Mohit and AlRegib, Ghassan},
booktitle={NeurIPS 2023 Second Table Representation Learning Workshop},
year={2023}
}
@article{chowdhury2025unified,
title={A unified framework for evaluating the robustness of machine-learning interpretability for prospect risking},
author={Chowdhury, Prithwijit and Mustafa, Ahmad and Prabhushankar, Mohit and AlRegib, Ghassan},
journal={Geophysics},
volume={90},
number={3},
pages={IM103--IM118},
year={2025},
publisher={Society of Exploration Geophysicists}
}- LIME: Ribeiro et al. (2016) - "Why Should I Trust You?" Explaining the Predictions of Any Classifier
- SHAP: Lundberg & Lee (2017) - "A Unified Approach to Interpreting Model Predictions"
- Actual Causality: Halpern (2016) - "Actual Causality"
- Counterfactuals: Wachter et al. (2017) - "Counterfactual Explanations without Opening the Black Box"
- Swartz (1997): "The Concepts of Necessary Conditions and Sufficient Conditions"
- Pearl (2009): "Causality: Models, Reasoning and Inference"
from counterfactual_generator import ForwardCounterfactualGenerator, GlobalScoreCalculator
import numpy as np
# Load your data
X_train, y_train = load_your_data()
X_test, y_test = load_your_test_data()
# Train your model
from sklearn.ensemble import GradientBoostingClassifier
model = GradientBoostingClassifier()
model.fit(X_train, y_train)
# Initialize CF generator
cf_gen = ForwardCounterfactualGenerator(
model=model,
feature_names=['feature1', 'feature2', ...],
n_perturbations=50
)
# Calculate global scores
calculator = GlobalScoreCalculator(cf_gen)
necessity, sufficiency = calculator.calculate_all_global_scores(
X_test, y_test, n_samples=100
)from xai_evaluator import XAIRobustnessEvaluator
# Initialize evaluator
evaluator = XAIRobustnessEvaluator(
model=model,
X_train=X_train,
feature_names=feature_names
)
# Run robustness analysis
results = evaluator.full_robustness_evaluation(
X_test=X_test,
necessity_scores=necessity,
sufficiency_scores=sufficiency,
top_k=7,
n_samples=100
)Issue: SHAP kernel explainer is slow
# Solution: Reduce background sample size
shap_explainer = shap.KernelExplainer(
model.predict_proba,
shap.sample(X_train, 50) # Reduced from 100
)Issue: Memory error with large datasets
# Solution: Reduce n_samples
python main.py --dataset large_data --n_samples 50Issue: LIME explanations vary significantly
# Solution: Increase num_samples in LIME
lime_explainer.explain_instance(
instance,
model.predict_proba,
num_samples=5000 # Increased from default
)Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Prithwijit Chowdhury - Georgia Institute of Technology
- Mohit Prabhushankar - Georgia Institute of Technology
- Ghassan AlRegib - Georgia Institute of Technology
- Ahmad Mustafa - Occidental Petroleum (for geophysics paper)
- This work is based on research conducted at the Omni Lab for Intelligent Visual Engineering and Science (OLIVES) at Georgia Tech
- Supported by the ML4Seismic Consortium and the Center for Energy and Geo Processing (CeGP)
- Thanks to the DHI Risk Analysis Consortium for providing data for the geophysics study
For questions or issues, please:
- Open an issue on GitHub
- Contact: pchowdhury6@gatech.edu
Keywords: XAI, Explainability, Interpretability, LIME, SHAP, Necessity, Sufficiency, Counterfactuals, Tabular Data, Machine Learning, Robustness

