Configuration (ProfilingConfig)¶
ProfilingConfig is the only tuning surface for
fit_profiler. Compose one immutable config from small,
single-responsibility section dataclasses.
In short
- Data goes to
fit_profilerdirectly; every tuning knob goes into oneProfilingConfig. clustering,archetypes,runtimeandevaluationalways exist with defaults.rules,explanations,edaandreportrun only when you set them.- A bare
ExplanationsConfig()runs PDP, permutation importance and a surrogate. - Every config is frozen: vary a knob with
dataclasses.replace.
from parleml_mli import (
ProfilingConfig, ClusteringConfig, RulesConfig, MinerConfig, AcceptanceGates,
ExplanationsConfig, PdpConfig, ReportConfig, fit_profiler,
)
config = ProfilingConfig(
clustering=ClusteringConfig(min_cluster_size=10, n_components=10),
rules=RulesConfig(miner=MinerConfig(
acceptance=AcceptanceGates(min_lift=1.3, min_tp_count=8))),
explanations=ExplanationsConfig(pdp=PdpConfig(n_features=6)),
report=ReportConfig(output_dir="out/"),
)
result = fit_profiler(
model=model, X=X_train, y=y, target_mask=(y == 1), # data stays flat
config=config, # every tuning knob
)
Two rules make the surface predictable:
- Presence enables a stage. An optional section left as
None(rules/explanations/eda/report) means "skip it" — there are no separate boolean toggles.clustering/archetypes/runtime/evaluationare always present (they have defaults). - Data is not config.
model/X/y/target_mask/ holdout splits (X_valid/X_testfor evaluation,X_holdout/y_holdout/holdout_basisfor the rules' Test numbers) /encoding_registry/task_typeare always direct arguments tofit_profiler— never part ofProfilingConfig.
Every config is frozen — vary a knob with
dataclasses.replace.
For the per-parameter tables of the standalone config records (EDAConfig,
RunSettings, CardinalityCaps) see
Configuration parameters.
ProfilingConfig¶
ProfilingConfig
dataclass
¶
ProfilingConfig(
clustering: ClusteringConfig = ClusteringConfig(),
archetypes: ArchetypeConfig = ArchetypeConfig(),
runtime: RuntimeConfig = RuntimeConfig(),
evaluation: EvaluationConfig = EvaluationConfig(),
rules: RulesConfig | None = None,
explanations: ExplanationsConfig | None = None,
eda: EDAConfig | None = None,
report: ReportConfig | None = None,
)
Everything :func:parleml_mli.fit_profiler needs that is not data.
Optional sections (rules / explanations / eda / report)
are None by default — a profiling run discovers archetypes only,
unless those stages are explicitly configured.
Clustering, archetypes & runtime¶
The always-present sections that shape archetype discovery.
ClusteringConfig
dataclass
¶
ClusteringConfig(
space_type: SpaceType | None = None,
min_cluster_size: int = 15,
min_samples: int | None = None,
cluster_selection_method: ClusterSelectionMethod = AUTO,
shap_distance_metric: ShapDistanceMetric = EUCLIDEAN,
top_n_features: int = 10,
enable_umap: bool = True,
umap_sample_size: int | None = 50000,
n_components: int | None = 10,
n_trials: int = 0,
tree_weights: "np.ndarray | None" = None,
)
Archetype-clustering geometry (HDBSCAN over the chosen space).
tree_weights
class-attribute
instance-attribute
¶
Optional per-feature weights for the leaf-space distance metric.
An array enables a callable weighted metric (and disables UMAP
pre-compression + sklearn tree acceleration). Excluded from __eq__ /
__hash__ (compare=False) because a NumPy array is unhashable and
has no scalar truth value under the frozen dataclass's generated methods.
ArchetypeConfig
dataclass
¶
ArchetypeConfig(
score_threshold: float | None = None,
contamination_min_coverage: float | None = None,
contamination_beta: float = 1.0,
min_odds_ratio: float = 3.0,
n_bootstrap: int = 0,
min_stability: float = DEFAULT_MIN_STABILITY,
)
Post-clustering survival filters: contamination, odds, stability.
RuntimeConfig
dataclass
¶
RuntimeConfig(
random_state: int = 42,
n_jobs: int = -1,
verbose: bool = False,
use_native_shap: bool = True,
shap_cache_path: str | None = None,
shap_cache_overwrite: bool = False,
)
SHAP computation, parallelism, determinism and caching.
EvaluationConfig
dataclass
¶
EvaluationConfig(
decision_threshold: float | str | None = None,
n_bootstrap: int = 0,
ci_alpha: float = 0.05,
multiclass_threshold_metric: str = "f1",
)
Holdout-evaluation knobs (the single decision-threshold source).
ReportConfig
dataclass
¶
ReportConfig(
output_dir: str | None = None,
persist_inference_data: (
bool | Literal["overwrite"]
) = False,
key_columns: list[str] | None = None,
)
One-call report generation + inference-data persistence.
Present (non-None on :class:ProfilingConfig) ⇒ the populated
result is written via result.generate_report(output_dir, ...) and,
when requested, the per-case inference-data sidecar is persisted.
The report is deterministic: no fit or report step calls a model. AI-written
narration is an annotation the host computes afterwards with
:func:parleml_mli.reporting.narrate_result and an injected :class:parleml_mli.ask.Ask.
Rules¶
Set ProfilingConfig(rules=RulesConfig(...)) to mine interpretable rules. See
the Rule extraction guide. Every rule gets Train numbers
on the mining rows and, when fit_profiler receives X_holdout /
y_holdout, Test numbers and a holds-up verdict — RulesConfig.holdout
sets the verdict's covered-row floor, and MinerConfig.wilson is the run's
confidence for every bound.
RulesConfig
dataclass
¶
RulesConfig(
engine: (
Literal["all"] | RuleEngine | tuple[RuleEngine, ...]
) = "all",
metric: AllClassMetric = "f1",
conf_threshold: float = 0.5,
cov_threshold: float = 0.0,
column_names: list[str] | None = None,
max_trees: int | None = DEFAULT_RULE_MAX_TREES,
miner: MinerConfig | None = None,
all_class: AllClassConfig | None = None,
holdout: RulesHoldoutConfig = RulesHoldoutConfig(),
class_workers: int = DEFAULT_RULE_CLASS_WORKERS,
)
Rule extraction. Present ⇒ run it; replaces rules_kwargs.
engine names the engines to mine: "all" (the default) runs the
positive miner and the sequential miner (:data:DEFAULT_RULE_ENGINES);
one engine name runs that engine alone; a tuple of distinct names runs
each of them, e.g. ("positive_miner", "sequential", "all_class")
adds the all-class engine — a slow mixed-class decision list, binary
models only — to the default pair. :attr:engines resolves the spec.
class_workers is how many one-vs-rest classes of a multiclass model are
mined at once, each in its own process (capped at the class count; 1
mines them one after another in this process). The rules do not depend on
it.
Raises:
| Type | Description |
|---|---|
ValueError
|
|
RulesHoldoutConfig
dataclass
¶
How rules are tested on held-out rows.
A rule gets a verdict only when it covers at least min_test_rows
held-out rows (counting covered rows, not positives); below that it has
too few test rows. With enough, it holds up when the Wilson lower bound
of its test precision — at the run's :class:WilsonConfig alpha /
one_sided, whatever its use_lower_bound — exceeds the test base
rate of its class. The Test numbers are measured whenever
held-out rows are given.
MinerConfig
dataclass
¶
MinerConfig(
max_rules: int | None = None,
max_combination_iterations: int | None = None,
max_candidates: (
int | None
) = DEFAULT_RULE_MAX_CANDIDATES,
time_budget_s: (
float | None
) = DEFAULT_RULE_TIME_BUDGET_S,
float_threshold: float = 1e-06,
catboost_combination_handling: str = "collapse-merge",
expansion: ExpansionGates = ExpansionGates(),
wilson: WilsonConfig = WilsonConfig(),
acceptance: AcceptanceGates = AcceptanceGates(),
dedup: DedupConfig = DedupConfig(),
business_value: BusinessValueConfig = BusinessValueConfig(),
)
Tuning surface for the positive / sequential rule miners.
Replaces the miner_kwargs dict. Composed from cohesive sections
(:class:ExpansionGates, :class:WilsonConfig, :class:AcceptanceGates,
:class:DedupConfig, :class:BusinessValueConfig) instead of one flat
field pile. random_state / verbose / column_names are sourced
from :class:RuntimeConfig and :class:RulesConfig, not duplicated here.
The top-level fields are the miner-wide knobs that do not belong to any
single gate (combination control, output cap, CatBoost handling). The
sequential miner ignores the whole :attr:dedup section. The positive
class is not a miner knob: :func:parleml_mli.rules.extract_rules resolves it
once (positive_class=) and every engine mines the {0, 1}
indicator with 1 positive. :attr:wilson is the run's confidence
for every engine (the all-class engine included).
max_candidates and time_budget_s bound one search (one engine, one
target class): the candidate pool grows with every tree combined, so the
search stops when the pool reaches max_candidates (deterministic) or
after time_budget_s wall-clock seconds (machine-dependent backstop),
keeps the best rules found so far and records why on
:attr:~parleml_mli.rules.RuleSetSummary.budget_stop. None disables either.
MinerConfig is composed from cohesive sub-sections rather than a flat field
pile — each groups one concern (the whole dedup section is ignored by the
sequential engine):
ExpansionGates
dataclass
¶
Loose gate applied during pairwise tree-combination.
A partial body must clear these thresholds to be worth expanding
further; the strict :class:AcceptanceGates then decides which of the
fully-grown candidates are actually emitted. Deliberately looser than
acceptance so promising conjunctions are not pruned before they are
complete: min_lift is capped at the resolved acceptance min_lift
(floored at 1), since lift cannot exceed 1 / prevalence.
WilsonConfig
dataclass
¶
Wilson score interval behind the precision bounds — the run's confidence.
precision_lower drives candidate scoring, the acceptance
min_precision_lower gate, ranking and the dedup Wilson tiebreak, and
the same interval bounds every reported precision, Train and Test alike,
and decides whether a rule holds up on held-out rows
(:class:RulesHoldoutConfig). one_sided=True makes each bound a
one-sided (1 - alpha) limit; use_lower_bound=False puts the raw
precision wherever a bound would appear in mining and in the reported
numbers — but not in the holds-up verdict, which always uses the
interval's lower bound at alpha / one_sided.
AcceptanceGates
dataclass
¶
AcceptanceGates(
min_lift: float | None = None,
min_tp_count: int | None = None,
min_coverage: float | None = None,
max_conditions: int = 6,
min_precision: float | None = None,
min_precision_lower: float | None = None,
)
Strict gate deciding which expanded candidates are emitted as rules.
The three data-aware gates — min_lift / min_tp_count /
min_coverage — default to None ("derive from the target's class
balance and dataset size"). Leaving them None lets
:func:parleml_mli.fit_profiler fill them from
:func:parleml_mli.rules.kwargs_suggest.suggest_rule_miner_kwargs
(prevalence-scaled min_lift, size-scaled min_tp_count /
min_coverage) via parleml_mli.pipeline.finalize._enrich_rules_config;
the leaf projection parleml_mli.rules.extraction_api._miner_config_to_kwargs
drops any still-None gate so the underlying miner falls back to its
own default. Set a literal to pin the gate and skip derivation.
DedupConfig
dataclass
¶
DedupConfig(
strategy: Literal[
"structural_then_coverage", "body_jaccard", "none"
] = "structural_then_coverage",
improvement_min_delta: float = 0.005,
coverage_jaccard_max: float = 0.7,
subset_coverage_jaccard_max: float = 0.5,
containment_max: float = 0.85,
min_subgroup_size_ratio: float = 0.4,
max_siblings_per_rule: int = 5,
diversity_jaccard_max: float = 0.9,
)
Near-duplicate suppression run after the acceptance gate.
Ignored wholesale by the sequential miner — grouping every dedup
knob into one section makes that a structural fact (pass no
:class:DedupConfig, or omit it, and there is nothing to ignore) rather
than a docstring caveat on a flat field list. strategy selects the
walk; the six structural_then_coverage knobs and the legacy
diversity_jaccard_max (body_jaccard only) tune it.
BusinessValueConfig
dataclass
¶
BusinessValueConfig(
value_tp: float = 10.0,
cost_fp: float = 1.0,
value_fn: Callable[[int, int], float] | None = None,
)
Net-value scoring of a candidate's confusion counts.
The default linear value_tp * tp - cost_fp * fp is used unless
value_fn supplies a custom (tp, fp) -> float payoff (which then
overrides value_tp / cost_fp).
AllClassConfig
dataclass
¶
AllClassConfig(
c: float = 0.25,
percent_training: float | None = None,
early_stop: float = 0.0,
rule_order: Literal["supp", "cov", "conf"] = "supp",
sort_by_class: bool | list[int] | None = None,
float_threshold: float = 1e-06,
catboost_combination_handling: Literal[
"collapse-merge", "skip-tree", "fail"
] = "collapse-merge",
)
Tuning surface for the all-class rule engine.
Replaces the all_class_kwargs dict (passthrough keys only — the
first-class metric / conf_threshold / cov_threshold /
column_names live on :class:RulesConfig, random_state on
:class:RuntimeConfig).
Global explanations¶
Set ProfilingConfig(explanations=ExplanationsConfig(...)) and enable each
artifact by giving its sub-section (leave it None to skip). See the
Global explanations guide.
A bare ExplanationsConfig() is not a no-op
Unlike the other optional sections, an ExplanationsConfig with no
per-artifact sub-section set resolves at consumption time to a sensible
default trio — pdp + permutation_importance + surrogate — so
"just explain the model" always does meaningful work. Use
ExplanationsConfig.default(...) to materialise that trio explicitly, or
set at least one sub-section to pin exactly what runs.
ExplanationsConfig
dataclass
¶
ExplanationsConfig(
pdp: PdpConfig | None = None,
ale: AleConfig | None = None,
shap_interactions: ShapInteractionsConfig | None = None,
surrogate: SurrogateConfig | None = None,
surrogate_residual: (
ResidualSurrogateConfig | None
) = None,
permutation_importance: (
PermutationImportanceConfig | None
) = None,
fairness: FairnessConfig | None = None,
psi: PsiConfig | None = None,
compacity: CompacityConfig | None = None,
error_tree: ErrorTreeConfig | None = None,
ovr_classes: bool | list[Any] | None = None,
)
Global model-interpretability artifacts.
Present ⇒ run :func:parleml_mli.explanations.explain. A non-None
per-artifact section enables that artifact (replacing the old
compute_explanations toggle + 10 *_kwargs dicts).
A bare ExplanationsConfig() (no section set) is resolved to a
sensible default trio — pdp + permutation_importance +
surrogate — at consumption time by
:func:resolve_explanations_config, so "just explain the model" is
never a silent no-op (§2.4). The config object itself is a faithful,
genuinely frozen record of what the caller asked for: it is never
mutated at construction (the previous __post_init__ /
object.__setattr__ self-mutation made "frozen" a half-truth,
broke dataclasses.replace(cfg, pdp=None) round-trips, and left
no way to express an intentionally-empty config — audit §1.3). Use
:meth:default to materialise the trio explicitly.
has_any_artifact
property
¶
True when at least one per-artifact section is set.
default
classmethod
¶
The default artifact trio, materialised explicitly.
ExplanationsConfig.default() ==
ExplanationsConfig(pdp=PdpConfig(),
permutation_importance=PermutationImportanceConfig(),
surrogate=SurrogateConfig()). Keyword overrides are applied
on top (e.g. default(ale=AleConfig()) adds ALE to the trio).
PdpConfig
dataclass
¶
PdpConfig(
features: list[str] | None = None,
n_features: int = 6,
grid_resolution: int = 30,
sample_size: int = 5000,
response_method: str = "auto",
target_class: Any | None = None,
categorical_features: list[str] | None = None,
random_state: int = 0,
)
Partial-dependence curves (:func:parleml_mli.explanations.pdp.compute_pdp).
features=None draws curves for the model's top n_features drivers —
by the profile's own importance when there is one, else by the model's
prediction sensitivity — never for identifier or datetime columns; an
explicit features list is drawn as given. Every column without a curve
is recorded with its reason on ExplanationsResult.pdp_selection.
AleConfig
dataclass
¶
AleConfig(
features: list[str] | None = None,
n_features: int = 6,
n_bins: int = 20,
sample_size: int = 5000,
response_method: str = "auto",
target_class: Any | None = None,
random_state: int = 0,
)
Accumulated-local-effects curves (:func:parleml_mli.explanations.ale.compute_ale).
Chosen like :class:PdpConfig's, among the numeric columns only; the
reasons for the columns without a curve land on
ExplanationsResult.ale_selection.
ShapInteractionsConfig
dataclass
¶
ShapInteractionsConfig(
top_features: int = 20,
sample_size: int = 5000,
target_class: Any | None = None,
random_state: int = 0,
)
SurrogateConfig
dataclass
¶
SurrogateConfig(
target_class: Any | None = None,
engine: EngineKey | None = None,
max_depth: int = 5,
min_samples_leaf: int = 20,
n_estimators: int = 1,
sample_size: int = 50000,
categorical_features: list[str] | None = None,
optimize: bool | dict[str, Any] = False,
random_state: int = 0,
holdout_fraction: float = 0.2,
target_kind: Literal[
"prediction", "residual"
] = "prediction",
residual_kind: Literal[
"auto", "signed", "squared", "logloss"
] = "auto",
)
Bases: SurrogateTuning
Glass-box surrogate of the model's predictions (or residuals).
ResidualSurrogateConfig
dataclass
¶
ResidualSurrogateConfig(
target_class: Any | None = None,
engine: EngineKey | None = None,
max_depth: int = 5,
min_samples_leaf: int = 20,
n_estimators: int = 1,
sample_size: int = 50000,
categorical_features: list[str] | None = None,
optimize: bool | dict[str, Any] = False,
random_state: int = 0,
holdout_fraction: float = 0.2,
residual_kind: Literal[
"auto", "signed", "squared", "logloss"
] = "auto",
)
Bases: SurrogateTuning
Surrogate fitted to the model's residuals (target_kind forced).
PermutationImportanceConfig
dataclass
¶
PermutationImportanceConfig(
n_repeats: int = 10,
scoring: str | None = None,
sample_size: int = 5000,
target_class: Any | None = None,
random_state: int = 0,
n_jobs: int = 1,
)
FairnessConfig
dataclass
¶
FairnessConfig(
sensitive_features: DataFrame | Series | None = None,
reference_group: dict[str, str] | None = None,
air_thresholds: tuple[float, float | None] = (
0.8,
None,
),
me_thresholds: tuple[float, float] = (-0.05, 0.05),
smd_thresholds: tuple[float, float] = (-0.5, 0.5),
target_class: Any | None = None,
sample_size: int = 50000,
max_distinct_numeric: int = 20,
min_group_size: int = 30,
random_state: int = 0,
)
PsiConfig
dataclass
¶
PsiConfig(
n_buckets: int = 10,
eps: float = 0.0001,
categorical_columns: list[str] | None = None,
binning_strategy: BinningStrategy = "union",
pooling_strategy: CategoricalPoolingStrategy = "union",
max_categories: int = 200,
)
ErrorTreeConfig
dataclass
¶
ErrorTreeConfig(
engine: EngineKey | None = None,
max_depth: int = 4,
min_samples_leaf: int = 30,
n_estimators: int = 1,
sample_size: int = 50000,
residual_threshold: float | None = None,
target_class: Any | None = None,
categorical_features: list[str] | None = None,
random_state: int = 0,
)
Next¶
- Configuration parameters:
EDAConfig,RunSettingsandCardinalityCaps - Profiling guide