Interpretability contract¶
The published, dependency-free surface for introspecting a fitted ml4 model. A
tool that explains models (ParleML MLI, or your own SHAP / rule code) imports
only these two objects and never touches autogluon.*:
InterpretablePipeline— the pipeline surface:transformraw input once, then reuse the encoded frame across probabilities and the member-introspection frame. ml4 computes no attributions itself; an explainer runs its own SHAP on aLeafModelHandle's estimator over that member frame.LeafModelHandle— one trained leaf estimator, unwrapped to its raw library object plus the function that reproduces the exact matrix it was trained on.
Both are rendered in full below.
In short
- An explainer imports only
InterpretablePipelineandLeafModelHandle, neverautogluon.*. - Every method takes and returns a column-named
pandas.DataFramewith real engineered feature names. LeafModelHandle.raw_estimatoris the plain library object (LGBMClassifier, …), ready for your own SHAP.FittedPipeline.feature_insightexplains the raw text and categorical columns; it is mined once at fit time and travels in the bundle.
One frame format, everywhere¶
Every method and callable on this contract takes and returns a plain,
column-named pandas.DataFrame. That is the whole promise:
- No
scipy.sparsematrices, no barenumpyarrays. - No positional
f0..column names — columns carry the real (engineered) feature names, so SHAP drivers and rule antecedents read in business terms. - No AutoGluon wrappers —
raw_estimatoris the library object (LGBMClassifier,XGBClassifier,ExplainableBoosting*, …) directly.
So a consumer never has to sniff types, densify a matrix, or rename columns
before running SHAP, partial dependence, or rule mining. FittedPipeline
implements this contract; see the FittedPipeline reference
and the inference guide.
InterpretablePipeline ¶
Bases: Protocol
The surface a consumer (e.g. MLI) reads — no AutoGluon types cross it.
A regulated run yields a pipeline whose :meth:leaf_models returns exactly one
handle; an ensemble returns one per member. :meth:transform once, then reuse
the encoded frame across every *_from_encoded call and
:meth:prepare_member_introspection_frame.
All frame-valued methods below take and return a column-named
:class:pandas.DataFrame — the single frame format promised by this module.
transform ¶
Raw input → the model's post-FE feature frame (global + fold-local FE).
A column-named pd.DataFrame — the encoded space every *_from_encoded
method and :meth:prepare_member_introspection_frame expects as input.
predict_proba_from_encoded ¶
predict_proba_from_encoded(
encoded: DataFrame,
*,
calibrated: bool = True,
member: Optional[str] = None
) -> DataFrame
Class probabilities from a :meth:transformed frame, as a pd.DataFrame
with one column per class label (calibrated by default).
predict_point_from_encoded ¶
Regression point predictions (original units) from a :meth:transformed frame —
the regression analogue of :meth:predict_proba_from_encoded; raises for
classification tasks. Lets per-row justify score regressions without probabilities.
prepare_member_introspection_frame ¶
The introspected base tree's member frame (global + its fold-local FE) — the space a consumer aligns SHAP / archetypes / rules on; raises only when nothing on the board is introspectable.
A dense, column-named pd.DataFrame — the same frame contract as
:attr:LeafModelHandle.trained_matrix_fn (it is that call for the introspected
leaf), so its columns equal that leaf's feature_names.
leaf_models ¶
leaf_models() -> List[LeafModelHandle]
The trained leaf estimators to introspect: one for a regulated model, one per member for an ensemble.
scorecard_points ¶
The deployed scorecard's points table, or None for every other model.
The one artifact ml4 extracts itself (see the module docstring): it hangs off the
AutoGluon wrapper, not off :attr:LeafModelHandle.raw_estimator, so it needs its
own accessor to reach a consumer at all.
LeafModelHandle
dataclass
¶
LeafModelHandle(
raw_estimator: Any,
trained_matrix_fn: Callable[[DataFrame], DataFrame],
weight: float,
feature_names: List[str],
kind: str,
classes_: "Optional[np.ndarray]" = None,
)
One trained leaf estimator, unwrapped from AutoGluon for introspection.
Every field is a plain, library-native value (no AutoGluon wrappers), so a
consumer can introspect the leaf without importing autogluon.
Attributes:
| Name | Type | Description |
|---|---|---|
raw_estimator |
Any
|
The library object — |
trained_matrix_fn |
Callable[[DataFrame], DataFrame]
|
Reproduces the exact feature matrix this leaf was trained
on from a :meth: |
weight |
float
|
The ensemble weight ( |
feature_names |
List[str]
|
The columns of the trained matrix, in the order the estimator
saw them — identical to |
kind |
str
|
The model-family tag
( |
classes_ |
'Optional[np.ndarray]'
|
The estimator's class labels, or |
The fit-time feature insight¶
The contract above explains the model. FittedPipeline.feature_insight
explains the columns the user supplied, and it is the one interpretability
artefact that cannot be derived on demand: the served bundle keeps no training
rows, and AutoGluon owns the fold-local encoders, so it is mined once during the
fit and travels in the bundle.
Two encoding-agnostic halves, both descriptive (never fed back as features):
| Kind | Question it answers | Direction |
|---|---|---|
keywords |
Which words distinguish one target group's rows from the rest? | none — c-TF-IDF relevance is non-negative |
categorical |
Which levels of this column push the target off its base rate? | signed target lift |
Groups are the run's classes for classification and quantile bins of the target
for regression, named at fit time (only the fit knows a bin's edges). Both
halves project into the same TextComponentInsight payload (rendered below), so
a consumer renders one card grid for either.
FeatureInsight
dataclass
¶
FeatureInsight(
categorical: Dict[str, Dict[str, Any]] = dict(),
keywords: Dict[
str, Dict[int, List["ScoredKeyword"]]
] = dict(),
group_names: Dict[int, str] = dict(),
group_sizes: Dict[int, int] = dict(),
)
Descriptive per-column insight mined once at fit time, served forever after.
keywords / group_names / group_sizes share one group space: the
encoded class index for classification, the quantile-bin index for
regression. Group display names are stored here rather than resolved by
the reader because only the fit knows what a regression bin's edges were —
keeping half the naming here and half at the reader would make a bin and a
class translate through different code paths for no gain.
insight_columns ¶
{kind: columns} for the kinds that actually carry a payload.
The capability gate reads this directly: a kind is absent — not present and empty — when nothing was mined, so "the tab exists" and "the tab has content" cannot disagree.
keyword_groups ¶
Ordered (group_id, display name) for the groups mined for column.
One ordering, used by every reader (insight cards and word cloud), so a class picker and the card grid can never disagree about which group is first.
keyword_insight ¶
keyword_insight(
column: str, *, top_n: int = DEFAULT_KEYWORDS_PER_GROUP
) -> "TextComponentInsight"
Project column's mined keywords into the shared insight payload.
Delegates to the same projector the unsupervised key-drivers surface uses, so a supervised class card and a clustering card render through identical code — the only difference is what a "group" means.
categorical_insight ¶
categorical_insight(
column: str,
*,
class_key: Optional[str] = None,
top_n: int = 15
) -> "TextComponentInsight"
Project column's stored target-lift stats into the shared insight payload.
compute_feature_insight ¶
compute_feature_insight(
df: DataFrame,
target_column: str,
*,
is_classification: bool,
cat_columns: Sequence[str] = (),
text_columns: Sequence[str] = (),
seed: int = 42,
max_text_columns: int = DEFAULT_MAX_TEXT_COLUMNS,
max_groups: int = DEFAULT_MAX_GROUPS,
max_rows: int = DEFAULT_MAX_KEYWORD_ROWS,
keywords_per_group: int = DEFAULT_KEYWORDS_PER_GROUP,
target_bins: int = DEFAULT_TARGET_BINS
) -> FeatureInsight
Mine the fit-time insight payload from the rows the model trained on.
df must still carry target_column in ORIGINAL units — a regression
y-transform is a modelling detail, and quoting a level mean or a bin edge in
log space would show the user a number that appears nowhere else in the
product.
Neither half raises on a difficult column: compute_categorical_stats
skips columns that are absent, constant or too high-cardinality to be a
category, and extract_keywords_by_column degrades a failing column to an
empty mapping. What is deliberately not here is a blanket try/except
around the whole producer — swallowing everything is precisely what let the
previous surface fail invisibly for every run.
TextComponentInsight
dataclass
¶
TextComponentInsight(
feature: str,
encoder: EncoderKind,
value_kind: ValueKind,
signed_source: Optional[SignedSource] = None,
class_key: Optional[str] = None,
class_keys: List[str] = list(),
global_stats: Optional[Dict[str, Any]] = None,
components: List[ComponentInsight] = list(),
)
The full insight payload for one encoded feature (one class slice).
to_dict ¶
Return a plain nested dict (lists/dicts/scalars) for JSON / the API.