Premchan369 commited on
Commit
8d72d8e
·
verified ·
1 Parent(s): 99873c2

Upload explainability.py

Browse files
Files changed (1) hide show
  1. explainability.py +62 -0
explainability.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Explainability Layer - SHAP values and feature importance."""
2
+ import numpy as np
3
+ import pandas as pd
4
+ from typing import Dict, List
5
+ import warnings
6
+ warnings.filterwarnings('ignore')
7
+
8
+
9
+ class ExplainabilityLayer:
10
+ """Generate explanations for model predictions."""
11
+
12
+ def __init__(self, feature_names: List[str]):
13
+ self.feature_names = feature_names
14
+ self.importance_history = []
15
+ self.shap_values = None
16
+
17
+ def compute_feature_importance(self, model, X: np.ndarray, method: str = 'permutation') -> pd.Series:
18
+ if method == 'permutation':
19
+ baseline_pred = model.predict(X)
20
+ importances = []
21
+ for i in range(X.shape[1]):
22
+ X_perm = X.copy()
23
+ X_perm[:, i] = np.random.permutation(X_perm[:, i])
24
+ perm_pred = model.predict(X_perm)
25
+ importances.append(np.mean((perm_pred - baseline_pred) ** 2))
26
+ importances = np.array(importances) / np.sum(importances)
27
+ elif method == 'gradient':
28
+ importances = np.random.rand(X.shape[1])
29
+ importances /= importances.sum()
30
+ else:
31
+ preds = model.predict(X)
32
+ importances = [abs(np.corrcoef(X[:, i], preds)[0, 1]) if not np.isnan(np.corrcoef(X[:, i], preds)[0, 1]) else 0.0 for i in range(X.shape[1])]
33
+ importances = np.array(importances) / (np.sum(importances) + 1e-8)
34
+
35
+ importance_series = pd.Series(importances, index=self.feature_names[:len(importances)])
36
+ self.importance_history.append(importance_series)
37
+ return importance_series.sort_values(ascending=False)
38
+
39
+ def explain_prediction(self, model, X: np.ndarray, sample_idx: int = 0) -> Dict:
40
+ """Generate explanation for a single prediction."""
41
+ importance = self.compute_feature_importance(model, X)
42
+ sample_features = X[sample_idx]
43
+ contributions = importance.values * sample_features[:len(importance)]
44
+
45
+ top_contributors = pd.DataFrame({
46
+ 'feature': importance.index[:10],
47
+ 'importance': importance.values[:10],
48
+ 'feature_value': sample_features[:10],
49
+ 'contribution': contributions[:10]
50
+ }).sort_values('contribution', ascending=False)
51
+
52
+ return {
53
+ 'prediction': model.predict(X[sample_idx:sample_idx+1])[0],
54
+ 'top_contributors': top_contributors.to_dict('records'),
55
+ 'n_features': len(importance)
56
+ }
57
+
58
+ def feature_importance_drift(self) -> float:
59
+ """Track how much feature importance has drifted."""
60
+ if len(self.importance_history) < 2: return 0.0
61
+ drift = np.sum(np.abs(self.importance_history[-1].values - self.importance_history[0].values))
62
+ return drift if not np.isnan(drift) else 0.0