2026-04-25
Session 40: Phase 5b: drain TimeSeriesExperiment.create_model
Engineering log for session 40.
The first TS verb is fully native. exp.create_model('arima') no longer touches legacy.create_model — the estimator resolves from the sktime registry, wires into the experiment's ForecastingPipeline, runs CV through the existing cross_validate helper, and returns a real sktime.forecasting.compose.ForecastingPipeline. Pattern mirrors the supervised create_model drain (s24) and unsupervised drain (s28).
ADDED — engine#
ADDED—TimeSeriesExperiment.create_modelinpackages/engine/pycaret/tasks/time_series.py. Native sktime path; returnsCreateResultwhosepipelineis a realForecastingPipeline. Accepts a registry ID string, a pre-constructed sktime forecaster, or aForecastingPipeline(extracts the inner forecaster). Wires the model in via_add_model_to_pipelinefrompycaret.utils.time_series.forecasting.pipeline. CV via the standalonecross_validatehelper frompycaret.utils.time_series.forecasting.model_selection(clones pipeline per fold, computes per-metric scores). Refits on fully_trainafter CV. Calls_set_last_metricssopull()returns the metrics. Handlescross_validation=False(skip CV, refit only).ADDED—TimeSeriesExperiment._build_ts_metric_registryhelper. Caches the TS metric containers (mae/rmse/mape/smape/mase/rmsse/r2/coverage) in_fit_state["metric_registry"]on first use. Parity with the supervised metric-registry drain (s32) —add_metric/remove_metriccan mutate it.ADDED—TimeSeriesExperiment._primary_sp_to_usehelper. Resolves the seasonal period for MASE / RMSSE scorers — falls throughself.seasonal_period→self._legacy.primary_sp_to_use→ 1.
CHANGED — tests#
CHANGED—tests/test_models.py::_unwrap_pipelinenow unwraps sktimeForecastingPipeline → TransformedTargetForecaster → forecasterso model-equality predicates see the bare forecaster. Previously only sklearnPipelinewas unwrapped.
ADDED — tests#
ADDED—packages/engine/tests/test_session40_ts_create_model_drain.py— 10 new tests:- Drain-lock for
create_model('naive')(poisonlegacy.create_model, verify native). - Drain-lock for classical forecasters (
arima/ets/exp_smooth/theta). cross_validation=Falsereturns metrics=None + fitted pipeline.- Pre-constructed sktime forecaster path (
NaiveForecaster(strategy='mean')). - Metrics DataFrame shape (5 rows: Fold 0/1/2 + Mean + Std; columns: MAE / RMSE / MAPE / MASE / R2).
pull()returns metrics from native run.predict_model(still legacy in 5b) accepts the natively-built pipeline.- Unknown registry ID →
ConfigurationError. - Object without
.fit→TypeError. - Metric registry caches on first use.
- Drain-lock for
INTERNAL#
INTERNAL— Why reusecross_validatefrompycaret.utils.time_series.forecasting.model_selection. That helper is a free function (not a method on legacy), it accepts a sklearn-stylescoringdict +additional_scorer_kwargsmap, and it already handles all the per-fold parallelism + alpha/coverage prediction-interval plumbing. Re-implementing it on top of sktime's bareevaluatewould either (a) lose interval coverage (used by thecoveragemetric), or (b) duplicate ~50 LoC of careful parallel orchestration. Calling the helper directly is a real drain — no legacy state involved — and skips the duplication.INTERNAL— Why_build_ts_metric_registryis onTimeSeriesExperiment, not in the base_get_metric_registry. The base helper bails for TS (task == TIME_SERIES → return None) so callers fall through to legacy. The TS helper here is the start of the migration — oncepredict_model/compare_models/ etc. drain in 5c, the base helper can be updated to delegate to this one.INTERNAL—_primary_sp_to_usereads_legacy.primary_sp_to_use. That's a transitional shortcut. Legacy auto-detects seasonal period via Fourier analysis when the user doesn't provide one. Phase 5c moves that detection out of legacy.
Session 40 delta summary#
| Metric | Session 39 end | Session 40 end |
|---|---|---|
| TS verbs drained (out of 6 verbs total) | 0 | 1 (create_model) |
legacy.create_model callsites for TS | 1 | 0 |
| Engine tests (fast + slow) | 191 | 201 |