Pick the entry point, pick the cross-validator, route the metadata,
read the report. The pipeline declaration is out of scope (see
build-ml-pipeline).
Before writing the evaluation call, output the following block
verbatim in your response. Each box must be backed by an actual
tool call or an explicit decision documented in the response.
-
skore.evaluate(...) is the entry point. It is a dispatcher
that returns the right report for the task and splitter
argument. Never hand-roll cross_val_score + manual metric
prints, and don't drop back to bare sklearn for evaluation. If you
see existing cross_val_score / cross_validate /
classification_report / mean_squared_error calls in the diff,
redirect them through skore.evaluate. Consult skore-api for
the exact signature.
Two data-passing forms — pick the one that matches the
estimator:
- sklearn-style:
skore.evaluate(estimator, X, y, splitter=...)
for any estimator whose fit is (X, y).
- env-dict-style:
skore.evaluate(learner, data={"X": X, "y": y, ...}, splitter=...) for a skrub SkrubLearner (its fit
takes a single environment dict mapping skrub.var(name=...)
names to values). This is the right form for the pipelines
produced by build-ml-pipeline.
X/y and data are mutually exclusive. The same split applies
to CrossValidationReport(...); EstimatorReport(...) uses
train_data= / test_data= for the env-dict equivalent of
X_train / y_train / X_test / y_test. See
skore-api/reports.md § "skrub interop".
-
Escalate to explicit report classes only when evaluate is too
coarse. The escalation order:
EstimatorReport — single fit on a held-out set (no CV); use
when CV is wasteful (e.g., evaluating the final model on all
data after CV has already been done).
CrossValidationReport — k-fold over one learner with access
to per-fold artifacts.
ComparisonReport — two or more learners side-by-side.
See references/reports.md for the escalation table; defer all
API details to skore-api.
-
Pick the cross-validator from the structural facts of the data
— not by default. The data tells you what splitter is correct.
The structural facts arrive at the X marker through
split_kwargs (set by build-ml-pipeline at declaration time).
Mapping rules:
split_kwargs content | Splitter |
|---|
groups | GroupKFold |
| temporal ordering | ask the user (see "Time-ordered data" below) |
| none | KFold (or RepeatedKFold for small / noisy data) |
Imbalanced classification does not change the choice — use
plain KFold / GroupKFold. See "Avoid by default" below.
Avoid by default:
- Stratified variants (
StratifiedKFold,
StratifiedGroupKFold, StratifiedShuffleSplit,
RepeatedStratifiedKFold) — they reduce across-fold variance
by construction, producing over-confident error bars on the
score. Don't reach for them on imbalance.
LeaveOneOut / LeaveOneGroupOut / LeavePGroupsOut —
high per-fold variance; aggregate hides the noise. Use
KFold / GroupKFold with 5–10 splits instead.
See references/cross-validation.md § "Avoid" for the reasoning.
Wiring details: references/metadata-routing.md.
Time-ordered data — user-question flow. When the data is
temporal, ask the user before picking a splitter:
- Is
TimeSeriesSplit sufficient, or do they want a custom
splitter (purged windows, calendar blocks, walk-forward)? If
custom, see references/custom-splitter.md.
- Should the time column stay as a covariate or be dropped from
the feature matrix? Encoders can extract calendar patterns
from a timestamp; the user's call.
If split_kwargs is empty and you cannot confirm there's no
structure (from build-time checks or from the user), do not
silently default. Return to build-ml-pipeline and ask the user
first.
-
Trust skore's metric defaults; override only on explicit user
request. skore.evaluate picks task-appropriate metrics
automatically (regression: MSE/RMSE/MAE/R²; binary: accuracy,
precision, recall, F1, ROC-AUC; multiclass: macro/micro variants;
multilabel: per-label + averages). Override only when the user
says so — e.g., "use RMSE", "report ROC-AUC". Don't pre-emptively
pin metrics or pass a scoring=... argument unless asked.
-
Custom splitter — only when sklearn doesn't have it. Examples
that justify one: purged-and-embargoed time-series CV (finance),
blocked spatial CV. The contract is small: split +
get_n_splits. See references/custom-splitter.md. Otherwise,
prefer the sklearn built-in.