Consuming a saved ProfilingResult¶
fit_profiler(...).save(path) is the producer. This guide is the
consumer side: how to load a saved profiling_result.joblib and read back
every artifact family — archetypes, held-out evaluation, mined rules, global
explanations, EDA, per-class structure, and similar-case retrieval — without
re-fitting the model.
In short
ProfilingResult.load(path)restores every computed artifact; nothing is refitted.- The full training
Xis never saved. PassX=again to recompute an artifact. - Every family is optional: check for
Nonebefore you read one. - A result from an incompatible schema is refused with
StaleArtifactError; recompute it. - AI narration is stored separately; reattach it with
attach_narration.
A runnable, end-to-end version of everything below ships as
demo_consume_result.py, which produces a tiny fixture on first run and then
reloads it fresh from disk. The demo is in the source checkout under
examples/demos/; it is not part of the installed wheel.
Load¶
from parleml_mli import ProfilingResult
result = ProfilingResult.load("out/profiling_result.joblib")
The loaded object exposes the full ProfilingResult
API — the same methods the live fit returns. Two things to know:
- The full training
Xis never persisted on the result. Artifacts that need it (rule re-extraction, some plots) accept an explicitX=argument at call time; everything already computed (rule text, fingerprints, cached metrics) is self-contained. - If the result was saved with
save(path, include_model=False), leaf-space retrieval raises at call time (the estimator is gone). Computed artifacts still load, but model-dependent operations such as native importance, glass-box structure and new predictions require a model.
load() checks the saved schema envelope and nested artifact schemas. An
unstamped or incompatible artifact raises parleml_mli.StaleArtifactError; recompute it
with the current library. Different recorded library versions produce warnings,
so a saved profile is not a promise of compatibility across arbitrary upgrades.
Attached AI narration is dropped by save() and must be reattached separately.
One-glance inventory¶
Start with the artifact summary — a presence-guarded headline of which families are populated and on which backend:
from parleml_mli._artifact_summary import format_artifact_summary
print(format_artifact_summary(result))
ProfilingResult artifacts [backend=native]
====================================================
archetypes : 6 (binary)
model_evaluation : -
rules : 23
explanations : pdp(4), permutation_importance
eda : 2 alert(s), 0 leakage finding(s)
stability : -
narration : -
Reading each artifact family¶
Every family is presence-guarded, so a consumer that doesn't know how the result was produced can safely check before reading.
Archetypes¶
result.summary_df # one row per surviving archetype (size + stats)
result.labels_ # cluster assignment per target-cohort row
result.clustering_result.n_clusters
Per-class structure¶
result.classes is a dict[str, ClassProfile] — a single entry for a binary
run, one per class for multiclass. Index the result directly by class key:
for key in result.class_keys:
profile = result[key]
print(key, len(profile.cluster_ids()), profile.base_target_rate)
Mined rules¶
For a single-class (binary) run the ruleset lives on the top-level
result.rules_ mirror; a multiclass run fans the rules out per class onto
result[key].rules (a {engine: RuleSetSummary} map):
# binary / single-class
if result.rules_ is not None and result.rules_.default_engine_summary is not None:
for rule in result.rules_.default_engine_summary.rules[:5]:
print(rule.text)
# multiclass
for key in result.class_keys:
for summary in result[key].rules.values():
for rule in (summary.rules if summary else [])[:5]:
print(key, rule.text)
Global explanations¶
expl = result.explanations_
if expl is not None:
if expl.pdp: # dict: feature -> PDP curve
print(list(expl.pdp))
if expl.permutation_importance is not None:
... # scalar family: present or None
EDA & held-out evaluation¶
if result.eda_ is not None:
print(len(result.eda_.alerts), "data-quality alert(s)")
if result.model_evaluation_ is not None:
print(result.model_evaluation_) # per-split Brier / ECE / calibration
Similar-case retrieval¶
Score brand-new rows against the saved archetypes — no re-fit, and in leaf space no model call is needed beyond the persisted estimator:
retrievals = result.retrieve_new_cases(X_new, top_k=3)
for r in retrievals:
print(r.nearest_cluster, r.is_novel, r.distance_to_nearest_medoid)
When X_target_orig= was supplied at fit time, each retrieval also carries the
business-readable nearest_original_features frame.
Re-rendering the report¶
A loaded result can regenerate its HTML/JSON report without a re-fit. The report is deterministic; to embed a narration the host stored, attach it first (see AI-written narration):
from parleml_mli.reporting import attach_narration
attach_narration(result, narration) # optional: the stored narrate_result dict
result.generate_report(output_dir="out")
Next¶
ProfilingResultreference: every accessor.- Decision support: explain new rows with the loaded result.