Explain an ml4 model¶
Time: about 10 minutes · You need: mli installed (Installation) and a binary classifier saved by ml4. You'll end with: the model's archetypes and rules in business column names, and reason codes for one new row scored by the deployed pipeline.
In short
- ml4 builds the model, mli explains it. In the app, an experiment's Interpretation tab does all of this for you, for every task.
- In Python, mli explains the best readable base tree on the ml4 board, which need not be
the deployed model.
pipeline.best_introspectable_leaf()picks it. Ml4OriginRegistryrolls engineered features back to the columns they came from.result.justifier(pipeline=...)scores a raw row with the deployed pipeline and explains it with the base tree.
1. Load the pipeline and pick the tree to explain¶
import parleml_ml4
import pandas as pd
pipeline = parleml_ml4.load_pipeline("out/bundle") # a FittedPipeline saved by ml4
choice = pipeline.best_introspectable_leaf() # None when nothing on the board is readable
estimator = choice.handle.raw_estimator # e.g. a LightGBM booster
print(choice.model_name, choice.is_strongest) # is_strongest: it is also the deployed model
best_introspectable_leaf() scans the board for the best-scoring base model mli can read,
preferring LightGBM, XGBoost and CatBoost over glass-box models. It returns None when nothing
qualifies, for example a run of foundation models only. Use
monitor_predictions on the pipeline's scores then.
2. Move your rows into the tree's feature space¶
The tree was trained on ml4's engineered features, not on your raw columns. Transform the raw rows once, then build the tree's own matrix:
df = pd.read_parquet("transactions.parquet")
y = df.pop("is_fraud") # a 0/1 target
X = pipeline.prepare_member_introspection_frame(pipeline.transform(df))
prepare_member_introspection_frame applies the chosen tree's own fold-level feature engineering,
such as target encodings, on top of the pipeline's global features.
The result is a plain, column-named DataFrame whose columns are the tree's feature names.
3. Profile it¶
from parleml_mli import ProfilingConfig, RulesConfig, TaskType, fit_profiler
from parleml_mli.adapters.ml4_encoding import Ml4OriginRegistry
result = fit_profiler(
model=estimator,
X=X,
y=y,
target_mask=(y == 1),
task_type=TaskType.BINARY,
positive_class=1, # a raw booster records no classes
encoding_registry=Ml4OriginRegistry(df.columns), # engineered name -> source column
config=ProfilingConfig(rules=RulesConfig()),
)
print(result.summary_df[["cluster_id", "n_target_cases", "lift"]])
This example uses a 0/1 target, which ml4 also codes as 0/1. With string labels or more than two
classes, the tree predicts ml4's class codes: map y to those codes before you profile. The app's
Interpretation tab does this for you.
To test the rules on rows the model never saw, pass held-out rows moved the same way as
X_holdout / y_holdout. See Rule extraction.
4. Explain one new row¶
justifier = result.justifier(pipeline=pipeline) # bind once, reuse for many rows
case = justifier.justify(df.iloc[[0]]) # a raw one-row DataFrame
print(case.prediction, case.matched_archetype)
for driver in case.shap_drivers:
print(driver)
The deployed pipeline produces the prediction and the decision threshold. The drivers, archetype, rules and neighbours come from the tree you profiled. When that tree is the deployed model, the two are the same model.
Details: glass-box structure of the deployed models
parleml_mli.adapters.ml4_pipeline.explain_pipeline(pipeline) returns one LeafExplanation per model
in the deployed pipeline: its kind, ensemble weight, feature names and native structure.
Coefficients, EBM shape functions and RuleFit rules come back as a dict; an opaque tree or
booster has native_explanation=None.
Next¶
- Working with ML4: the contract mli reads and what each view describes.
- Decision support: batch reason codes and local sensitivity.