importance and heter_score
Description
Part of the interactive API guide: the twin
scalars. importance for how much the mean effect moves the output,
heter_score for how much the average hides, both in the output's
units.
Reading time
Approx. 4' to read.
Two scalars, one scale
pdp.importance(0) # 0.0144: how much the MEAN effect moves
pdp.heter_score(0) # 5.8008: how much the per-instance effects SPREAD
Both are std type quantities in the output's units, so they are
comparable across features, across feature types, and, in magnitude, across
methods. On the conditional interaction model of
the plot page, x_0 scores near zero importance and huge
heterogeneity: its mean effect cancels out while the individual effects are
wildly spread. That is precisely the feature a global average hides.
✅ Read them as orthogonal axes, not as one ranking. High importance with low heterogeneity means the mean curve is the whole story. High heterogeneity means one curve is not enough, whatever the importance. The two axes drawn together are the triage plane.
What exactly they measure
importance: the dispersion of the mean effect over the data distribution. A flat curve scores ~0; a swinging curve scores high. For a linear model it recovers|coefficient| · std(x).heter_score: the RMS ofeval_heterover the feature's own data values, frequency weighted over levels for categorical features, bridged by the feature's dispersion for the derivative based methods so every method lands on the same y unit scale. Read it as "a typical instance's effect deviates from the mean effect by about this much".
No y, ever
effector never sees ground truth labels. These are properties of the fitted effect, not a loss based or permutation importance.
On real data
On the bike sharing rig, both axes at once:
pdp.importance("hr") # 0.6576: the mean effect swings hard
pdp.heter_score("hr") # 0.4707: and the instances still disagree a lot
hr is the top right corner of the triage plane: important and
heterogeneous, the feature to hunt regions for.
The whole vector
imp = pdp.importances() # (D,)
order = np.argsort(-np.nan_to_num(imp)) # most important first
imp -> [0.086 0.227 0.051 0.658 0.008 0.029 0.018 0.067 0.212 0.093 0.021]
One call, one (D,) array: hr (0.658), yr (0.227) and temp (0.212)
carry the model.
NaN means unsupported, not unimportant
Feature types a method cannot explain (e.g. DerPDP on a nominal
feature) return NaN, with one UserWarning naming them.
The regional bridge
Both scalars take mask= / rule=, and that is not a convenience; it is
the engine of the regional analysis:
pdp.heter_score("hr") # 0.4707 global
pdp.heter_score("hr", rule="workingday == no") # 0.3274 inside the subregion
Conditioning on workingday explains away a third of hr's spread. Note
the rule string speaks the schema's level names (no), not internal
codes.
heter_score(feature, mask) is the quantity
find_regions minimizes: a good split is one whose
subregions score much lower than the parent. When you read a partition tree,
every chip's heter is this call on that node's mask.
Where to next
find_regions: put the scores to work- The interactive API: back to the guide's map
eval: the same quantities, as curves