2026-04-25
Session 43: Phase 5c (cont.): drain TimeSeriesExperiment.tune_model
Engineering log for session 43.
The fourth TS verb is fully native. exp.tune_model(forecaster) no longer touches legacy.tune_model — it wraps sktime's ForecastingGridSearchCV / ForecastingRandomizedSearchCV around the experiment's preprocess pipeline, uses the registry container's tune_grid / tune_distributions (or custom_grid=), and refits the best hyperparameters via the drained create_model.
ADDED — engine#
ADDED—TimeSeriesExperiment.tune_modelinpackages/engine/pycaret/tasks/time_series.py. Resolves estimator fromForecastingPipelineor bare sktime forecaster; looks up matching container byclass_def; converts pycaretDistributionobjects to sklearn-compatible distributions viaget_base_distributionsfor random search; wires forecaster into preprocess pipeline + prefixes param keys; runsForecastingGridSearchCV(search_algorithm='grid') orForecastingRandomizedSearchCV(default'random'); strips prefix offbest_params_; refits via nativecreate_model(**best_params)so we get standard Fold/Mean/Std metrics. Supportschoose_better=True(re-runs the input estimator and keeps whichever wins onoptimize),return_tuner=True(returns(TuneResult, search_obj)tuple),custom_grid=, and arbitrary**kwargsforwarded to the search constructor.ADDED—_lookup_ts_container(cls)helper. Looks up a TS container in_fit_state["model_registry"]by itsclass_defso we can resolve a bare forecaster back to its container's tune_grid.ADDED—_score_from_metrics(metrics, col)static helper. Pulls a scalar from theMeanrow of a CV metrics DataFrame for thechoose_bettercomparison.
ADDED — tests#
ADDED—packages/engine/tests/test_session43_ts_tune_model_drain.py— 10 new tests:- Drain-lock for
tune_model. best_paramskeys match the container'stune_distribution(NaiveContainer:strategy/sp).search_algorithm='grid'yieldsForecastingGridSearchCV.- Default
'random'yieldsForecastingRandomizedSearchCV. custom_grid=overrides container defaults.pull()returns tuned model's CV metrics.- String estimator →
TypeError(must pass throughcreate_modelfirst). - Bad
optimize=→ConfigurationError. return_tuner=Truereturns(TuneResult, search)tuple.- End-to-end
create + tune + predictchain with all 4 legacy verbs poisoned.
- Drain-lock for
INTERNAL#
INTERNAL— Why convert pycaret Distribution objects. TS containers shiptune_distributiondicts whose values are pycaret-specificDistributioninstances (UniformDistribution,CategoricalDistribution, etc.). sklearn'sParameterSampleronly accepts sklearn-compatible distributions (scipy.statsrvs or sequences). Theget_base_distributionsutility converts via each Distribution's.get_base()method. Grid search doesn't need this — pycaret grids are already plain lists.INTERNAL— Why refit viacreate_modelinstead of usingsearch_obj.best_estimator_. Two reasons: (a) the search runsrefit=Falsesobest_estimator_would be unfitted; (b) calling our drainedcreate_modelgets us the standard Fold/Mean/Std metrics DataFrame for free, whichchoose_betterneeds. The downside is one extra CV pass — acceptable for the drain milestone.INTERNAL—choose_bettershort-circuit. Whenchoose_better=True, we re-create the input estimator (a fresh instance with the same hyperparameters) to compute its CV metrics for comparison. Could be optimised by reading metrics off the input pipeline's history, but that requires plumbing we haven't built. Same approach legacy uses; safe baseline.
Session 43 delta summary#
| Metric | Session 42 end | Session 43 end |
|---|---|---|
| TS verbs drained (out of 6) | 3 (create / predict / compare) | 4 (+ tune_model) |
legacy.tune_model callsites for TS | 1 | 0 |
| Engine tests (fast + slow) | 218 | 228 |