Inspection Reference
philanthropy.inspection
Model-agnostic interpretability helpers for donor-scoring estimators.
explain_donor_scores(estimator, X, method='predict_proba', *, baseline=None, top_k=3, class_index=None)
Explain why each donor got their score, one row of X at a time.
:func:donor_feature_importance says which signals matter to the model
overall; this says which signals moved this donor's score. For every row
and every feature, the feature is replaced with a typical (baseline) value,
the row is rescored, and the change is reported:
contribution = score(row) - score(row with feature set to baseline)
A positive contribution means the donor's actual value pushed the score up relative to a typical donor; a negative one pulled it down. This is a one-at-a-time, dependency-free stand-in for SHAP: contributions are exact for additive models but do not sum to the score in general, and correlated features can share or mask credit. A value already close to the baseline gets a contribution near zero, however important the feature.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
estimator
|
fitted estimator
|
Any fitted estimator (or :class: |
required |
X
|
array-like or pandas.DataFrame of shape (n_samples, n_features)
|
Donors to explain. May contain |
required |
method
|
str
|
Name of the scoring method, e.g. |
"predict_proba"
|
baseline
|
array - like
|
The typical values substituted in. Either the training feature
matrix (2-D), from which the per-column median is taken (the most
frequent value for non-numeric columns, |
None
|
top_k
|
int or None
|
Number of features reported per row, largest absolute contribution
first. |
3
|
class_index
|
int
|
Column to explain when |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Long format, |
Raises:
| Type | Description |
|---|---|
ValueError
|
If no baseline is given and the estimator stores none, or if the
baseline's length does not match the number of columns in |
Examples:
>>> import numpy as np
>>> from sklearn.linear_model import LinearRegression
>>> from philanthropy.inspection import explain_donor_scores
>>> X = np.array([[0.0, 1.0], [1.0, 1.0], [2.0, 1.0], [3.0, 1.0]])
>>> model = LinearRegression().fit(X, 2 * X[:, 0])
>>> out = explain_donor_scores(model, X[[3]], "predict", baseline=X, top_k=1)
>>> out[["feature", "contribution"]].round(2).to_dict("records")
[{'feature': 0, 'contribution': 3.0}]
Source code in philanthropy/inspection/_explain.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | |
donor_feature_importance(estimator, X, y, *, feature_names=None, n_repeats=10, random_state=None, scoring=None)
Permutation feature importance for a fitted donor-scoring estimator.
Answers "which donor signals move this model's score?" for any fitted
PhilanthroPy / scikit-learn estimator, including calibrated or
gradient-boosted models (e.g. :class:~philanthropy.models.MajorGiftClassifier)
that do not expose feature_importances_, by measuring how far a scoring
metric drops when each feature's values are randomly shuffled. It is a
dependency-free alternative to SHAP for explaining and auditing donor scores.
Because attribution is computed by scoring against held-out y, run this on
a validation split (not the training data) for an honest read.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
estimator
|
fitted estimator
|
Any fitted estimator implementing |
required |
X
|
array-like or pandas.DataFrame of shape (n_samples, n_features)
|
Feature matrix to permute. |
required |
y
|
array-like of shape (n_samples,)
|
True targets used to score each permutation. |
required |
feature_names
|
sequence of str
|
Column labels for |
None
|
n_repeats
|
int
|
Number of times each feature is permuted. |
10
|
random_state
|
int, RandomState instance or None
|
Controls the permutation shuffling for reproducibility. |
None
|
scoring
|
(str, callable or None)
|
Scorer passed through to
:func: |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
One row per feature with columns |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |