Construct and fit
Description
Part of the interactive API guide: the five
engines, their shared constructor, and .fit() as the one place to
customize the method.
Reading time
Approx. 4' to read.
The lifecycle
flowchart LR
C["<b>construct</b><br/>PDP(X, model)"] --> F["<b>fit</b><br/><i>the only model touch</i>"]
F --> Q["<b>query, free</b><br/>plot · eval · importance<br/>heter_score · find_regions"]
Q -. "zero model calls" .-> F
Construct the engine once; it holds what is expensive. Every question you ask afterwards is answered from cached local effects, without touching the model again.
The five constructors
pdp = effector.PDP(X_test, predict)
ale = effector.ALE(X_test, predict)
rhale = effector.RHALE(X_test, predict, jacobian)
shapdp = effector.ShapDP(X_test, predict)
derpdp = effector.DerPDP(X_test, predict, jacobian)
They differ in what they compute; they do not differ in how you call
them. The derivative based engines, RHALE and DerPDP, take the jacobian
as a second callable; see the input layer for writing
one per framework.
The real data thread of this guide is bike sharing, the same dataset as the report guide, with a gradient boosted trees model:
data = effector.datasets.BikeSharing() # standardized UCI bike sharing
model = HistGradientBoostingRegressor(random_state=21).fit(data.x_train, data.y_train)
pdp = effector.PDP(
data.x_train,
effector.adapters.from_sklearn(model),
schema=schema, # names, types, level names, units; see the input guide
nof_instances=5000,
)
Trees have no useful jacobian, so on this rig the derivative based engines
sit out; every other page runs on pdp (and an ale twin) built exactly
like this.
Every constructor accepts the same keyword arguments:
| argument | default | meaning |
|---|---|---|
schema |
None |
names, types, level names, units; see the input layer |
nof_instances |
10_000 |
the subsample the engine is built on |
random_state |
21 |
seed for that subsample |
axis_limits |
None |
override the per feature evaluation range |
.fit() is where you customize
ale.fit("all") # everything, defaults
ale.fit(["hr", "temp"], binning_method="dp") # custom config
.fit() is optional
Any eval/plot on an unfitted feature silently computes what it needs
with the defaults. fit is the place to customize: its kwargs
(binning, order, scope) are deliberately not accepted by eval/plot,
so a feature's configuration lives in exactly one call.
The shared arguments are features (an index/name, a list, or "all") and
centering, the feature's default centering mode: False (raw),
True/"zero_integral" (zero mean), or "zero_start" (the curve starts at
0). The rest is per method:
pdp.fit(features="all", centering=False, use_vectorized=True)
No binning: the grid is implicit. use_vectorized trades one big model
call for many small ones when memory is tight.
ale.fit(features="all", centering=True, binning_method="fixed", order=None)
Classic ALE bins with a "fixed" grid; order overrides the level order
of ordinal features.
rhale.fit(features="all", centering=True, binning_method="dp",
order=None, binning_scope="global")
Variable size bins by dynamic programming ("dp", the RHALE idea);
also accepts "agglomerative", "quantile", "fixed", or a configured
instance from effector.axis_partitioning. binning_scope="global"
freezes one binning for every subregion query, so regional numbers stay
comparable.
shapdp.fit(features="all", centering=True, binning_method="dp",
binning_scope="global")
SHAP values are computed per instance, then binned like RHALE for the curve and its spread.
👉 Defaults differ on purpose: PDP fits uncentered (centering=False, ICE
curves are meaningful raw), the accumulation based methods fit centered
(centering=True, an ALE curve is only defined up to a constant).
📄 The knobs at work, on a model built to punish bad defaults, are in
Customize .fit().
Where to next
plot: the next verb- The interactive API: back to the guide's map
- Customize
.fit(): the knobs, at work