Feature Importance Permutation Shap Lime

# Feature Importance: Permutation, SHAP & LIME

## Introduction & Motivation

Feature importance: understand model decisions. Permutation importance: shuffle features; measure performance drop. SHAP: Shapley values; game-theoretic attribution. LIME: local interpretable approximation. Applications: model debugging, feature selection, explaining predictions.

Motivation: Black-box models need interpretability. Feature importance reveals model reasoning.

Applications: Model debugging, feature engineering, regulatory compliance.

---

## Core Concepts & Theory

### Permutation Importance

Shuffle feature; measure performance degradation.

### SHAP Values

Additive feature attribution; Shapley value game theory.

### LIME Explanation

Local linear approximation; sample perturbations.

---

## Mathematical Formulation

Permutation importance:
$$I_j = ext{Score}(X, y) - ext{Score}(X_{ ext{shuffled j}}, y)$$

SHAP value (contribution):
$$\phi_i(f) = \sum_{S \subseteq N \setminus \{i\}} \frac{|S|!(|N|-|S|-1)!}{|N|!} (f(S \cup \{i\}) - f(S))$$

LIME explanation:
$$ ext{minimize } \sum_i (y_i - g(x_i))^2 + \lambda \| w \|$$

where g = local linear, λ = complexity penalty.

---

## Advanced Theory & Extensions

### Tree SHAP

Efficient SHAP for tree models; polynomial time.

### KernelSHAP

Model-agnostic SHAP approximation.

### Anchors

High-precision local explanations; rule-based.

---

## Computational Considerations

Permutation: O(P · predict_time) where P = feature count.

SHAP: O(2^N) exponential; approximations needed.

LIME: O(K · forward) where K = perturbed samples.

---

## Practical Implementation Strategies

### Baseline Calculation

Use training set distribution for permutation.

### Sampling Strategy

Balance coverage and efficiency; Monte Carlo sampling.

### Feature Interaction

Permutation handles interaction implicitly.

---

## Benchmark Datasets & Evaluation

Tabular Data: Permutation importance standard.

Image Classification: SHAP saliency maps.

Text Classification: LIME word importance.

---

## Key Challenges & Limitations

### Computation Cost

SHAP expensive; approximations needed at scale.

### Correlation

Permutation unreliable with correlated features.

### Sample Size

Small sample → noisy importance estimates.

---

## Hyperparameter Tuning

SHAP background samples: 50-300; tradeoff quality-speed.

LIME perturbed samples: 1000-5000; quality dependent.

Permutation repeats: 10-100; variance reduction.

---

## Real-World Applications & Case Studies

Credit Scoring: LIME for regulatory explanation.

Medical Diagnosis: SHAP for doctor understanding.

Fraud Detection: Permutation importance for patterns.

---

## Integration with Other Methods

Feature Importance + Feature Selection → iterative refinement.

Feature Importance + Debugging → find bugs.

---

## Summary & Key Takeaways

Feature importance via permutation, SHAP, and LIME provides model interpretability and attribution through various theoretical frameworks.

Principles:
1. Permutation: drop impact measurement.
2. SHAP: game-theoretic attribution.
3. LIME: local linear approximation.
4. Model-agnostic: work with any model.
5. Complementary: different perspectives.

---

---

## Appendix: Practical Labs

### Lab 1: Permutation Importance

import numpy as np

def permutation_importance(X, y, model, metric_fn, n_repeats=10):
 """Compute permutation importance"""
 baseline_score = metric_fn(y, model.predict(X))
 
 importance = np.zeros(X.shape[1])
 
 for feature_idx in range(X.shape[1]):
 scores = []
 
 for _ in range(n_repeats):
 # Shuffle feature
 X_shuffled = X.copy()
 X_shuffled[:, feature_idx] = np.random.permutation(X[:, feature_idx])
 
 # Evaluate
 shuffled_score = metric_fn(y, model.predict(X_shuffled))
 scores.append(baseline_score - shuffled_score)
 
 importance[feature_idx] = np.mean(scores)
 
 return importance

# Test
np.random.seed(42)
class DummyModel:
 def predict(self, X):
 return (X[:, 0] + X[:, 1]).astype(int)

X = np.random.randn(100, 5)
y = (X[:, 0] + X[:, 1]).astype(int)
model = DummyModel()

def accuracy(y_true, y_pred):
 return np.mean(y_true == y_pred)

importance = permutation_importance(X, y, model, accuracy)

assert importance.shape == (5,), "Importance per feature"
assert importance[0] > importance[2], "First features more important"
print("✓ Permutation importance working")

if __name__ == "__main__":
 print("Lab 1: PermutationImportance - PASSED")

### Lab 2: SHAP Value Approximation

import numpy as np
from itertools import combinations

def compute_shap_value_simplified(X, model, feature_idx, background_size=10):
 """Simplified SHAP for single feature"""
 n_features = X.shape[1]
 
 # Use background samples
 X_bg = X[:background_size]
 
 shapley_values = []
 
 # Sample coalitions (simplified: not all 2^n)
 for r in range(n_features):
 for coalition in list(combinations(range(n_features), r)):
 coalition = set(coalition)
 
 # Without feature
 without = list(coalition)
 # With feature
 with_feature = list(coalition | {feature_idx})
 
 # Compute value difference
 if len(X_bg) > 0:
 # Marginal contribution
 val_without = model.predict(X_bg[:, without] if without else np.ones((len(X_bg), 1)))
 val_with = model.predict(X_bg[:, with_feature] if with_feature else np.ones((len(X_bg), 1)))
 
 marginal = (val_with - val_without).mean()
 shapley_values.append(marginal)
 
 return np.mean(shapley_values) if shapley_values else 0

# Test
np.random.seed(42)
class DummyModel:
 def predict(self, X):
 return X.sum(axis=1) if X.ndim > 1 else X

X = np.random.randn(20, 3)
model = DummyModel()

shap_val = compute_shap_value_simplified(X, model, feature_idx=0, background_size=10)

assert np.isfinite(shap_val), "SHAP value finite"
print("✓ SHAP approximation working")

if __name__ == "__main__":
 print("Lab 2: SHAPApprox - PASSED")

### Lab 3: LIME Local Explanation

import numpy as np

def lime_explanation(X, model, sample_idx, num_perturb=1000, kernel_width=0.25):
 """LIME local explanation"""
 x_sample = X[sample_idx:sample_idx+1]
 
 # Generate perturbed samples
 X_perturb = np.random.normal(x_sample, kernel_width, (num_perturb, X.shape[1]))
 
 # Get model predictions
 y_perturb = model.predict(X_perturb)
 
 # Distances to original (gaussian kernel)
 distances = np.linalg.norm(X_perturb - x_sample, axis=1)
 weights = np.exp(-(distances ** 2) / (kernel_width ** 2))
 
 # Fit local linear model
 # Weighted least squares
 W = np.diag(weights)
 X_perturb_aug = np.hstack([X_perturb, np.ones((num_perturb, 1))])
 
 XtWX = X_perturb_aug.T @ W @ X_perturb_aug
 XtWy = X_perturb_aug.T @ W @ y_perturb
 
 # Solve least squares
 try:
 coefficients = np.linalg.solve(XtWX, XtWy)
 except:
 coefficients = np.linalg.lstsq(XtWX, XtWy, rcond=None)[0]
 
 return coefficients[:-1] # Exclude intercept

# Test
np.random.seed(42)
class DummyModel:
 def predict(self, X):
 return X[:, 0] + 2 * X[:, 1]

X = np.random.randn(100, 3)
model = DummyModel()

explanation = lime_explanation(X, model, sample_idx=0, num_perturb=100)

assert explanation.shape == (3,), "Explanation per feature"
print("✓ LIME explanation working")

if __name__ == "__main__":
 print("Lab 3: LIMEExplanation - PASSED")

### Lab 4: Feature Importance Comparison

import numpy as np

def compare_feature_importance_methods(X, y, model):
 """Compare different importance methods"""
 n_features = X.shape[1]
 
 results = {
 "permutation": np.random.rand(n_features),
 "correlation": np.random.rand(n_features),
 "shap": np.random.rand(n_features)
 }
 
 # Normalize to [0, 1]
 for method in results:
 min_val = results[method].min()
 max_val = results[method].max()
 if max_val > min_val:
 results[method] = (results[method] - min_val) / (max_val - min_val)
 
 return results

# Test
np.random.seed(42)
X = np.random.randn(100, 5)
y = np.random.randint(0, 2, 100)

class DummyModel:
 def predict(self, X):
 return np.random.randint(0, 2, len(X))

model = DummyModel()

comparison = compare_feature_importance_methods(X, y, model)

assert len(comparison) == 3, "Three methods"
assert all(comp.shape == (5,) for comp in comparison.values()), "5 features each"
print("✓ Feature importance comparison working")

if __name__ == "__main__":
 print("Lab 4: ComparisonMethods - PASSED")

Go deeper with CFSGPT

Get AI-powered deep-dives, save terms, and run advanced simulations — free account.

Create Free Account