Changelog
Unreleased
Fixed
- Display units honor the schema's
scale_y: every surface labeled "(target units)" —effector.plot_triage,CALM.plot_triage, and the report's importance/heterogeneity bars, triage plane, ranked tables, ledger heter columns, andheter_thresholdchip — now bridges the model-unit scalars byscale_y["std"], so a model trained on a standardized target reads in the target's own scale (matching the curve plots, which already rescaled). Unbound reports render the same as bound ones:Reportstampsscale_y/scale_x_list, and the unbound curve fallback applies them. The engine verbs (importance,heter_score) and all stamped/serialized payloads stay in model-output units, sofind_regionsthresholds and old dicts are unaffected. - HTML report surfaces missed by the
scale_ybridge: the decision-sequence table's heterogeneity column, the per-feature and global-baseline chips, the rejected-split note, and the per-leaf statistics (figure captions and the unbound leaf table) still rendered raw model-unit scalars while the rest of the page was bridged. They now use the samescale_y["std"]bridge and the ranked table's.4gformat, so one page reads in one unit. The partition-tree<pre>dump keeps model units by design (it is the verbatimPartition.show()payload).
[0.5.0] - 2026-07-14
Breaking
Regional*classes removed (RegionalPDP,RegionalDerPDP,RegionalALE,RegionalRHALE,RegionalShapDP) with no backward-compatibility shim. Regional questions are now asked on the global effect object viafind_regions(feature) -> Partition(design contract R12: partitions are values, not stored state). Migration:RegionalPDP(X, f).fit(0); r.summary(0); r.plot(0, i)→pdp = PDP(X, f); pdp.fit(0); part = pdp.find_regions(0); part.show(); part.plot(i). The oldspace_partitioner=fit kwarg becomes thefinder=kwarg offind_regions;r.eval(0, i, xs, heterogeneity=True)(tuple) splits intopart.eval(i, xs)+part.eval_heter(i, xs).- Two-block lifecycle (R14):
fitcomputes the frame-gated local effects — the only model touch — and every summary (centering included) is a memoized, model-free reduction on top. Thepoints_for_centeringfit kwarg and therequires_refitmachinery are gone; changingcenteringateval/plottime never recomputes local effects behind your back. - Scalar units contract:
heter_scoreandimportancenow return values in output units (RMS over the data), directly comparable to the target's scale and to each other. Slope-scale methods (RHALE, DerPDP) are bridged by the feature's std; nominal features use order-free all-pairs level differences.ShapDPno longer overridesimportancewithmean(|φ|)— it inherits the shared default. Any thresholds tuned against the old variance-flavored numbers must be recalibrated. Report.to_html(path)writes the file and returnsNone(it used to return the multi-megabyte HTML string, echoing it in interactive shells).
Added
GlobalEffectBase.find_regions(feature, *, finder="best", candidate_conditioning_features="all") -> Partitionon every global class — a model-free heterogeneity split search (every candidate scored byheter_score(feature, mask), re-summarized from the cached local effects). Returns aPartitionvalue object (effector.Partition/effector.Region) withshow/eval/eval_heter/plot/to_dict; nothing is stored on the effect.- A finder protocol on
space_partitioning(Base.find_regions): a finder consumes only(score_fn: mask->float, data, metadata, its own config)and returns aPartition, so new finders plug in with no changes elsewhere. The min-points / degeneracy (BIG_M) guard lives in the finder, never in the effect. - Named split proposers on the built-in finders:
categorical_proposer=("one_vs_rest"default |"subsets"|"ordered"— natural order for ordinal levels, similarity seriation for nominal, or an explicit order |"multiway") andcontinuous_proposer=("threshold"default |"quantiles"— one k-way candidate per child count at the marginal quantiles), both also accepting a proposer instance (effector.proposers). Defaults unchanged; the finder'sproposer_factoryattribute remains the raw extension seam. - An invisible bounded-LRU masked-summary memo on the effect, keyed by
(feature, fit_epoch, mask), so repeated masked calls (the split search re-proposing candidate masks, a plot after a search) skip re-summarization. It is semantically transparent — a refit bumps the epoch and invalidates it; it never changes an answer, only its latency. effector.explain(data, model, ...) -> Report— a one-call pipeline: fit once, rank features byimportance(R13), draw the mean-effect + heterogeneity curves for the top-k, andfind_regions(R12) on the heterogeneous ones. Returns a serializableReportvalue (effector.Report) withshow()(importance-ranked table + region trees),plot_importance(),to_html()(a self-contained page — every figure inlined as a base64 PNG, no external assets), andto_dict()/from_dict()(round-trips without an effect). All model calls happen through the singlefit; the rest is model-free, so the cost does not grow withtop_k.importance(feature, mask=None) -> floatandimportances(mask=None) -> (D,)on every global class (design contract R13) — the μ-twin ofheter_score: the dispersion of the mean effect, evaluated the same way (continuous → std over the (masked) data values; discrete → frequency-weighted std over levels). PDP, ALE, RHALE and ShapDP all use that one default; DerPDP is the sole override (bridgedmean(|derivative|), since its mean effect is already a derivative). Model-free, centering-invariant (nocenteringkwarg), masked variant free through the memo.importancesreturnsNaN(with oneUserWarning) for feature types a method cannot explain. effector never seesy, so loss/permutation importance is out of scope by construction.effector.adapters— model wrappers that make the numpy-only final pass explicit:from_sklearn(estimator),classifier_proba(predict_proba, class_),from_torch(module), andcheck(model, X)(the two-row handshake probe). An adapter returns a plain callable; it never installs one behind your back.- Feature names as strings everywhere: every verb that takes a feature (
plot,eval,importance,heter_score,find_regions, ...) accepts the schema name ("hr") as well as the index. - Plural
find_regions(features=...): a list,"all", or"heterogeneous"(above-medianheter_score) returns{name: Partition}— the inputselect_regionsandplot_triageeat. select_regions(partitions=None, ..., min_r2_gain=0.01) -> CalmSequence— greedy explained-variance selection across features: starting from the GAM (every feature global), each round applies the split with the largest sequential R² gain and stops when no remaining split addsmin_r2_gainofVar(f̂). Returns the chain[GAM, calm1, ...]of CALM snapshots (effector.CALM/effector.CalmSequence— serializable value objects with stamped per-featureimportances/heter_scores,plot_triage,bind(effect)); rejected splits land in.skippedwith a reason (redundant/below_threshold).CalmSequence.show()prints the same EXPLAINED VARIANCE / REJECTED SPLITS tables as the report. Derivative-scale methods (DerPDP) raise: summing their curves does not approximatef̂.- Explained variance in the report:
explainopens with the headline — the share of the model's variance the GAM (global curves only) and the final CALM (with the accepted splits) reproduce — and the report carries the full decision sequence as a ledger (table + bar): sequential ΔR² per accepted split, a counterfactualsolocolumn per rejected one. Features whose split was rejected keep their global read; the regional plots are demoted with the reason. effector.rules— the predicate algebra under regions:Interval,LevelSet,Rule(a normalized conjunction of per-feature conditions) withcontains/intersect/refine/formatand a string parser that resolves schema level names (rule="workingday == no").Partition/Regionare rule-primary (v2 serialization: rules + stamped stats, never masks); masked verbs acceptrule=sugar wherevermask=is accepted.effector.compare(effect_a, effect_b, feature=...)— overlay fitted engines on one feature's axis — andeffector.plot_triage(effect, partitions=None)— the importance × heterogeneity plane, with before/after arrows when partitions are passed.grid(feature)and.explain(...)on every engine: the model-free evaluation grid, and the one-liner without leaving a constructed session.- Categorical capability matrix completed:
DerPDPhandles ordinal/nominal features via ICE level differences (transition bars, no jacobian on discrete axes);RHALEon a nominal feature falls back to ALE instead of raising — no method/type holes remain. - Dataset loaders
effector.datasets.MedicalCosts,AirfoilSelfNoise,AdultIncome(+ the corresponding real-example notebooks).
Changed
- Plot redesign across every figure: titles carry the identity (feature · method · global/regional), rules read
where (workingday = no) and (temp < 6.86)and resolve schema level names, categorical plots draw at the labeled levels with per-level counts, one tick/legend discipline, semantic theme tokens, ALE panel redesign, triage labels repel.report.to_html()reads like the pipeline: triage overview first, per-feature global + regional, before/after arrows, shared y across the page and shared x per feature. Report.show()prints tables — DATA & MODEL (inscale_yunits, matching the figures), the EXPLAINED VARIANCE ledger with thesolocolumn, REJECTED SPLITS with reasons, and the ranked FEATURES table (#regions= accepted leaves) — followed by the accepted partition trees. Unicode box-drawing by default,show(ascii=True)for terminals that mangle it. R² and every ΔR² print as%— one unit everywhere (read+18.3%as an absolute move on the 0–100% R² scale).- ShapDP payloads are pure numpy (binned means replace
scipy.interpolatesplines on the eval path) and the global-effect base dispatches continuous/categorical kernels in one place — no output change, one seam for new methods. - internal (no output change): tightened the compute/draw boundary (R1).
visualization.plot_pdp_iceno longer computes the mean line or std/std-err band from the raw ICE table — the PDP method hands it the pre-computed curve + band (the band is now definitionallysqrt(eval_heter), the single source of heterogeneity). PDP's per-instancenorm_constreduction moved from anp.ndimbranch in the baseevalto an overridable_mean_norm_consthook. Centering-grid resolution now flows from the singlehelpers.NOF_INTERNAL_POINTSknob instead of a hard-coded30.
Notes
Partition.plot(idx)inherits each global class's ownplotdefaults (e.g. PDP still defaultsheterogeneity="ice"), so there is no visual change versus the old per-method regional plot wrappers.
Fixed
- global effects: a centering-triggered auto-refit (e.g.
fit(centering=False, order=[...])theneval/plotwith centering) no longer discards the method-specificfitkwargs —order/binning_method(anduse_vectorized) are replayed from the originalfit, overriding onlycentering, instead of silently falling back to the defaults - the split search no longer overflows on a high-cardinality categorical conditioning feature (the subset enumeration is capped)
- the numerical jacobian tolerates models that return
(N, 1)column vectors instead of(N,) Report.to_htmlrenders a note instead of crashing when an accepted rule pins the feature of interest to a single value inside a leaf (no axis to draw a curve over)Report.show/to_html: the DATA & MODEL header now speaks the figures'scale_yunits (it printed raw model-output units); the#regionscolumn counts a partition's leaves (it counted tree nodes, disagreeing with the regional section); the HTML rejected-split notes say%like every other surface (two-ptleftovers)
[0.4.0] - 2026-07-06
Breaking
- one
schema=argument replaces the metadata kwargs on every public constructor:feature_names=,target_name=(all classes) andfeature_types=,cat_limit=(regional classes) are removed; passschema={"feature_names": ..., "feature_types": ..., "cat_limit": ..., "target_name": ..., "scale_x_list": ..., "scale_y": ...}(or aneffector.Schema) instead — every field optional, explicit fields win over inference - SHAP configuration moved to the constructor:
budget,shap_explainer_kwargs,shap_explanation_kwargsare no longerfitkwargs onShapDP/RegionalShapDP(andRegionalShapDPgainsshap_values=for parity);fitkeeps only the analysis args - all
fitsignatures are keyword-only afterfeatures;points_for_mean_heterogeneityremoved from regionalfit(internal, shares one grid constant withpoints_for_centering) DerPDP.plot/RegionalDerPDP.plot:dy_limitsrenamed toy_limits(its only axis); ALE/RHALE plots droppednof_points(the curve is drawn exactly at the bin limits)utils.get_feature_typesdeprecated (delegates toeffector.ingestion.infer_feature_types) and its vocabulary changed to the three-way taxonomy
Added
- effector is numpy-only (R10):
datamust be a 2-D numeric numpy array andmodel/model_jacarenumpy → numpycallables, called exactly as given (never wrapped) — a DataFrame passed to a constructor is rejected with a pointer tofrom_dataframe.effector.from_dataframe(df) -> (X, schema)is the opt-in convenience that reads a DataFrame's names/dtypes/category labels into a numpy matrix + populatedSchema(it never touches the model); pandas stays an optional dependency, never imported on the numpy path - three-way feature taxonomy
continuous/ordinal/nominal(aliasescont/cat), stored on every class asfeature_types+feature_metadata; heuristic type inferences (low-cardinality int) emit aUserWarningnudging an explicit declaration - categorical features as feature of interest (docs/method_semantics.md is the exactness contract): PDP/ICE evaluate only at the observed levels (bars + jittered ICE dots); ALE accumulates adjacent-level differences (exact for ordinal; nominal defaults to the encoded order with a documented caveat, or
order=[...]/order="similarity"KS-seriation onfit); RHALE does discrete derivatives + Greedy/DP adaptive level grouping (ordinal only); ShapDP does per-level mean/variance with a step lookup; DerPDP and RHALE-on-nominal raise clear errors; centering andheter_scorebecome frequency-weighted over levels - regional effects on categorical features:
search_partitions_when_categoricalnow defaults toTrue, the heterogeneity of a categorical feature of interest is the frequency-weighted per-level variance, and every regional method finds subgroups for per-level effects (seenotebooks/synthetic-examples/08_categorical_features.ipynb) scale_x_list/scale_yaccepted at construction (schema) as plot defaults; plot-time dicts override,Falsedisablesmodels.ConditionalCategoricalclosed-form ground-truth model;effector.ordering.similarity_order(scipy-only Molnar/iml seriation)- input contract spec:
docs/design.mdR10 (accepted data types,Schemametadata argument, three-way feature taxonomy, define-or-infer, model-call rule, scaling precedence) anddocs/method_semantics.md(the exacteval/eval_heter/heter_score/plotformulas per method and feature type) category_namesschema field: per-feature human-readable level labels shown on categorical plot axes instead of the numeric codes; resolved to a value-keyed map at ingest, so regional nodes that restrict a categorical feature to a subset of its levels still label correctlyFeatureEffectfacade on a categorical feature of interest drops the methods its type doesn't support (e.g.RHALEon a nominal) with aUserWarning, overlays the rest at the observed levels, and raises only when nothing is left
Changed
- unified defaults:
nof_instancesis 10,000 everywhere except SHAP-based classes (1,000) —RegionalALE/RegionalRHALEwere 100,000 andFeatureEffect1,000;nof_ice/nof_shap_valuesdefault to 100; plot grids default to 100 points; oneheterogeneityvocabulary on all plots (False | "std" | method-native,True≡"std") - type inference now runs on the full data (before
nof_instancessubsampling); regional node objects and facade sub-methods inherit the parent's resolved metadata instead of re-inferring from subsets space_partitioning.compile:categorical_limitrenamed tocat_limitPDP/RegionalPDPdefault centering is nowzero_integral(wasFalse), soeval(centering=None)and the global/regional plots center consistently withALE/ShapDP- the method / feature-type capability matrix (e.g.
RHALEandDerPDPon nominal) is enforced at regionalfittime, not only later atplot, sofit/summary/plotstay consistent for an unsupported feature of interest
Fixed
ALE/RHALE.plot()crashed on a categorical feature whose level codes are not0..K-1(e.g. ordinal hours1..24): the plot grid was built from positional codes0..K-1and rejected byeval; it now draws at the observed level valuestreedisplay no longer crashes on per-featureNoneentries inscale_x_listhelpers.indices_within_limitsraisesValueErrorinstead of a bareassertwhenaxis_limitsexclude every point- removed the phantom
avg_outputconstructor docstring onShapDPand the staleice_non_vectorizeddocstring example helpers.prep_data: the subsampleindices(stored asself.indiceson every effect object) are now original-relative — they indexdataas passed in even when theaxis_limitsfilter dropped rows (data_in[indices] == data_out), giving a stable handle back to the user's rows
[0.3.0] - 2026-07-04
Added
random_stateon every public effect-class constructor (PDP,DerPDP,ALE,RHALE,ShapDP, the 5 regional variants, andFeatureEffect); default21, so two identical constructions give identicaleval/fit/plotoutput out of the box,Noneopts into fresh randomness. The seed also drives plot-time ICE/SHAP-scatter subsampling and is passed to the shap/shapiq explainer (seed=/random_state=) unless overridden viashap_explainer_kwargs. No effector code touches the globalnp.randomstate anymore.
[0.2.1] - 2026-07-01
Changed
- modernized GitHub Actions CI: replaced
black/flake8/isortwithruff, added a Python 3.10-3.13 test matrix, gated PyPI publishing behind a main-ancestry check + test run + wheel smoke test, added a docs build-check on PRs, pinned workflow permissions, added concurrency cancellation, and addeddependabot.yml - PyPI releases now auto-create a matching GitHub Release with notes from this changelog
Fixed
- fixed a latent
NameErrorinRegionalEffectBase._fit_feature's string-basedspace_partitionerfallback (effector/regional_effect.py) - fixed
prep_dale_fit_paramsvalidatingmax_nof_binstwice instead ofmin_points_per_bin(effector/helpers.py)
[0.2.0] - 2025-07-21
Changed
- updated the guide that measures runtimes of regional methods
- moved
shap/shapiqto an optionaleffector[shap]extra, so the core install stays lightweight (numpy,scipy,matplotlib,tqdm);ShapDP/RegionalShapDPnow raise a clearImportErrorpointing topip install effector[shap]if used without it - moved
ucimlrepoto thetutorialsextra
Removed
- dropped the unused
overridesdependency
[0.1.12] - 2025-07-13
Fixed
- fixed bug in
project.toml, added dependency tooverrides
[0.1.11] - 2025-07-10
Added
- added codecov to the project
Fixed
- fixed all notebooks to work with the latest version of Effector
- fixed bug in
RegionalPDPplots, wherecenteringwas not working properly, it was set toFalseand the user defined argument was not being passed.
[0.1.10] - 2025-06-18
Fixed
- bug in
project.toml
[0.1.9] - 2025-06-18
Fixed
- bug in github actions
[0.1.8] - 2025-06-18
Added
- NO2 real example
Fix
- fixed documentation errors, fixed node indexes
Changed
- added dependecies to
requirement-dev.txt
[0.1.7] - 2025-05-08
Added
- added organizations the that support the project
[0.1.6] - 2025-04-14
Fix
- fixed bug in
project.toml, added dependency toshapiq
Changed
- REAME.md and index.md: added refereces to effector
[0.1.5] - 2025-03-24
Added
- added
ucimlrepoto the dependencies space_partitioningmodule withBestandBestDepthWiseclasses for space partitioning.space_partitioning.Best(default) is a node-wise partitioning, i.e., it splits each node based on the split that maximizes the heterogeneity drop.space_partitioning.BestDepthWiseis a depth-wise partitioning, i.e., all nodes of a certain level are split based on the same condition.
Fixed
- fixed bug in
space_partitioning.Best(); partitioning now checks that the absolute heterogeneity should be over a threshold to be considered a valuable split - fixed bug in RegionalPDP plots, where
centeringwas not working properly, it was set toFalseand the user defined argument was not being passed.
Changed
- default plot titles now display full method name, e.g.,
Accumulated Local Effectsinstead ofALE. - added support for shapiq backend in
shap_dpandshap_regional_dp(added as alternative toshap) - set the default value of
heter_small_enoughto 0.001 (from 0.00) - set the default value of
centeringtoTrueforRegionalPDPplots (fromFalse) - set the default value of
centeringtoFalseforRegionalDerPDPplots (fromTrue)
[0.1.4] - 2025-02-26
Changed
- default plot titles now display full method name, e.g.,
Accumulated Local Effectsinstead ofALE. - update all notebooks with new names
[0.1.3] - 2025-02-25
Changed
- shap_dp (both global and regional) can now take custom arguments for the SHAP explainer
[0.1.2] - 2025-02-22
Changed
- all plots return a
fig, axtuple, if the user wants to modify the plot further. - default plot titles now display full method name, e.g.,
Accumulated Local Effectsinstead ofALE. - changed README.md to reflect the new changes.
Added
- license
- documentation for space partitioning methods
[0.1.1] - 2025-02-17
Changed
-
Updated GitHub Actions workflows:
-
Modified
pulish_to_pypi.ymlto be triggered only on major or minor version changes. -
Modified
publish_documenation.ymlto be triggered only on major or minor version changes. -
add changelog.md to the documentation
[0.1.0] - 2025-02-17
Added
- Initialized changelog file and added basic versioning structure.