From ct
Deep time-series ML operational intuition — walk-forward CV with gap, temporal-leakage audit, probabilistic forecasting (pinball, CRPS, conformal), hierarchical reconciliation, foundation models (Chronos, TimesFM, MOIRAI), drift detection. Load when designing CV under temporal ordering, foundation-model vs tuned baseline, probabilistic intervals, reconciliation, or drift monitoring. Skip for tabular ML (use `classical-ml-pitfalls`), causal inference, or survival analysis. Triggers on: "walk-forward", "TimeSeriesSplit", "temporal leakage", "MASE", "pinball loss", "CRPS", "conformal prediction", "Chronos", "TimesFM", "MOIRAI", "N-BEATS", "PatchTST", "MinT", "ADWIN", "statsforecast", "neuralforecast".
How this skill is triggered — by the user, by Claude, or both
Slash command
/ct:time-series-mlThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Concise operational pointers for deep time-series and forecasting work where models tend to be shallow.
Concise operational pointers for deep time-series and forecasting work where models tend to be shallow.
Assumes you already know what a time series is, basic ARIMA/ETS, and supervised ML. This skill covers the operational layer — walk-forward CV correctness, leakage vectors, stationarity tests, multi-seasonal decomposition, multi-step strategy, probabilistic + conformal intervals, hierarchical reconciliation, the 2024–2026 foundation-model landscape, neural architectures with DLinear as the bar — current as of late 2025/early 2026.
Load when the task is:
gap in TimeSeriesSplit to avoid leakage between fold boundary and lag horizonstatsforecast.cross_validation, mlforecast, sktime splitters, sklearn TimeSeriesSplithd/D after ADF+KPSSseasonal_naive skill-score benchmark before claiming a "win"Do NOT load for: general supervised tabular ML (rows i.i.d.; use classical-ml-pitfalls), causal inference / DiD / synthetic control, LLM text generation, recommender / sessionised event sequences, survival analysis.
sklearn.model_selection.TimeSeriesSplit(n_splits=5, max_train_size=None, test_size=None, gap=0). The footgun: gap=0 by default. If features include lag_k of the target (or rolling stats with window w), the test fold uses targets the training fold's last rows already saw as features. Set gap ≥ max(lag_horizon, rolling_window) or, for direct-h forecasting, gap = h − 1. Without test_size, fold size = n_samples // (n_splits + 1).
sktime.split.ExpandingWindowSplitter(fh, initial_window, step_length) grows train each fold; SlidingWindowSplitter keeps it fixed (better when distribution drifts). fh is a ForecastingHorizon — relative or absolute. Both accept step_length < len(fh) to overlap test windows.
statsforecast.cross_validation(df, h, n_windows, step_size, refit) — cutoffs cutoff_max = T − h, cutoff_min = cutoff_max − (n_windows − 1)·step_size. refit=False trains once at earliest cutoff; refit=True per window; refit=k every k windows. For neural / global models with expensive fits use refit=False early, then a final refit=1 rerun for headline numbers. step_size = h non-overlapping; step_size = 1 true rolling-origin.
mlforecast uses the same cross_validation API; the recursive feature builder will silently use future rows for expanding_mean etc. unless you pass lag_transforms (lag-only).
(a) Future regressors at predict time — exogenous X must be known at the cutoff (calendar, promotions yes; weather forecasts only with the same lead time). statsforecast/neuralforecast call these futr_exog_list; if a column is unknown at horizon, declare hist_exog_list.
(b) Rolling stats on full series — compute pandas.Series.rolling(w).mean().shift(1) not .rolling(w).mean(). The shift(1) is the leakage fix everyone forgets.
(c) Target encoding using future labels — encode using expanding(min_periods=...).mean().shift(1).
(d) Normalization fit on full series — StandardScaler.fit(y) on the entire series leaks variance from test; fit per-train-fold. NeuralForecast/MOIRAI handle with per-window scaler_type='standard'/'robust'/'identity'.
(e) Imputation with bidirectional fill — bfill/interpolation across the cutoff. Use forward-only.
statsmodels.tsa.stattools.adfuller: H0 = unit root (non-stationary). Reject p<0.05 → "stationary".statsmodels.tsa.stattools.kpss(regression='c'|'ct'): H0 = stationary. Reject p<0.05 → "non-stationary". Opposite direction.d=0.d≥1.t), don't difference.D for season m: y_t − y_{t−m}. For monthly data m=12. ARIMA(p,d,q)(P,D,Q)_m. Use nsdiffs (Canova-Hansen / OCSB) for D, ndiffs for d — pmdarima.utils and statsforecast.arima.AutoARIMA both expose this.λ=0. scipy.stats.boxcox returns optimal λ. Invert before scoring.STL(period, seasonal=7, robust=True) (statsmodels) — robust to outliers; period must be odd ≥3.statsforecast.MSTL with season_length=[24, 24*7]) for multi-seasonal data (daily-with-weekly hourly). Beats classical decompose.sin(2πk·t/P), cos(2πk·t/P) for k=1..K. Prophet defaults: yearly K=10, weekly K=3, daily K=4. Higher K → more wiggle, more overfitting. For NeuralForecast/mlforecast use mlforecast.target_transforms.Differences and pass calendar Fourier columns as static_features or dynamic_features.changepoint_prior_scale (default 0.05) controls trend flexibility; reduce to 0.001 for stiff, raise to 0.5 for noisy. n_changepoints=25 over the first 80% of history. seasonality_mode='additive'|'multiplicative'. Holiday DataFrame with holiday, ds, optional lower_window, upper_window. Battle-tested but maintained at low velocity; NeuralProphet (PyTorch) adds AR + lagged covariates and is the contemporary alternative.ŷ_{t+1} back as input for t+2..t+h. Errors compound; unbiased only when f is linear and correctly specified (Hyndman 2014). Library default in mlforecast.MLForecast.h separate models, one per step. Avoids error compounding, no inter-step coherence, scales poorly in h. NeuralForecast does direct by default (output head sized h); statsforecast MFLES, Theta, AutoARIMA are recursive.ŷ_{t+1}, append, retrain, repeat. Best of both at training cost. darts.models.RegressionModel(multi_models=True, ...) exposes the choice.L_τ(y, ẑ_τ) = max(τ(y−ẑ_τ), (τ−1)(y−ẑ_τ)). NeuralForecast: loss=DistributionLoss('Normal'|'StudentT'|'NegativeBinomial') or loss=MQLoss(quantiles=[0.1,0.5,0.9]). Coverage of the 80% interval should be ≈80% on holdout — measure it (MIS / interval coverage). Calibration ≠ point accuracy; a model with worse RMSE may have well-calibrated 95% PIs and be more useful for inventory.∫(F̂(z) − 𝟙{y ≤ z})² dz; for an ensemble it's the average of |x_i − y| − 0.5·|x_i − x_j|. CRPS reduces to MAE at the median; pinball loss summed over a dense quantile grid approximates 2·CRPS.MapieTimeSeriesRegressor with EnbPI (Xu & Xie 2021) — bootstrap residuals, build PIs with approximately marginal coverage 1−α without distributional assumptions. Exchangeability is violated in TS; use re-weighted / adaptive variants (ACI, AgACI). 2025: NeurIPS paper on conformal under change points; arXiv 2511.13608 is the current "gentle intro." TimeGPT uses split conformal under level=[80,95].Nixtla/hierarchicalforecast: BottomUp, TopDown(method='proportions'|'forecast_proportions'), MiddleOut, MinTrace(method='ols'|'wls_var'|'mint_shrink'), ERM. MinT (mint_shrink) uses residual covariance — minimum-variance unbiased reconciliation, generally beats BU/TD on real data (Wickramasuriya, Athanasopoulos, Hyndman 2019). Probabilistic coherent: BootstrapReconciler, Normality, PERMBU.| Model | Architecture | Size | Niche |
|---|---|---|---|
| Chronos / Chronos-Bolt (Amazon) | T5 enc-dec, value tokenization via quantile binning | Tiny 9M → Large 710M; Bolt 250× faster, 20× less mem | Univariate zero-shot; Bolt-Base 205M beats original Chronos-Large |
| Chronos-2 (Oct 2025, arXiv 2510.15821) | 120M encoder-only, alternating time/group attention | 120M | Multivariate joint forecasting + covariates; tops GIFT-Eval late 2025 |
| TimeGPT (Nixtla) | Closed API; direct multi-step, conformal PIs | — | level= PIs; zero-shot + fine-tune (finetune_steps, finetune_loss, finetune_depth); anomaly endpoint |
| TimesFM (Google) | Decoder-only | 200M; v2.5 (Sep 2025) 16K context, native probabilistic head | Held #1 GIFT-Eval until Chronos-2 |
| MOIRAI (Salesforce) | Masked encoder, multi-patch, any-variate attention, mixture distribution head | LOTSA 27B obs | MoE adds sparse experts; MOIRAI 2.0 (Nov 2025) decoder-only, multi-token prediction |
| Lag-Llama | Decoder-only on lag features (Feb 2024) | open | No exogenous support — limits practical use |
| Toto (Datadog) | 151M, Student-t mixture head, factorised attention | 151M | SOTA on Datadog BOOM (350M obs, 2807 series); competitive on GIFT-Eval/LSF; Apache 2.0 |
| Moment (CMU, 2024) | T5-style multi-task | — | Forecast/classify/impute/anomaly |
Practical: zero-shot foundation models beat seasonal-naive on heterogeneous, low-volume, no-history series. They typically lose to a tuned global LightGBM/NHITS on a single rich domain with adequate history (M5-style). Always benchmark against SeasonalNaive and AutoETS before celebrating.
y=0, asymmetric (over-forecast penalised more in percentage terms), incentivises low forecasts. Avoid for intermittent demand.mean(|e_t|) / mean(|y_t − y_{t−m}|) over training, where m is seasonality (m=1 non-seasonal). Scale-free, defined unless series constant, MASE<1 ⇔ beats seasonal-naive. Default reporting metric for forecasting comps (M4, M5, GIFT-Eval).Σ|e_t| / Σ|y_t| — preferred over MAPE for retail.1 − metric_model / metric_baseline; baseline is SeasonalNaive. Positive = win, negative = lost to naive.river.drift.ADWIN(delta=0.002) — adaptive window, statistical guarantees, slowly adapts.river.drift.PageHinkley(min_instances=30, delta=0.005, threshold=50, alpha=1−1e-4) — cheaper, lowest RAM, often the most reliable in 2025 comparative studies.Operational pattern: monitor MAPE_t over a sliding 7-day window of 1-step residuals; trigger retrain if window MAPE > 1.5× training MAPE for 3 windows in a row, or any drift detector fires. Refit cadence guidance: daily forecasts → weekly refit; hourly → daily incremental fit; minute-level → online incremental (river, statsforecast with refit=1).
add_seasonality(prior_scale=...) and increase changepoint_prior_scale to absorb regime shifts.detect_anomalies — conformal residuals, zero-shot. Toto/Chronos-2 likewise expose forecast-residual anomaly scoring.Footgun: a true anomaly during a seasonal peak gets masked by the seasonal component; always detrend+deseasonalise before scoring, and inspect the seasonal component separately for changepoints.
statsforecast + mlforecast + neuralforecast + hierarchicalforecast + nixtla (TimeGPT) under one cross-compatible cross_validation API; coreforecast shared C kernels.Before recommending a non-trivial time-series change (CV gap, multi-step strategy, foundation-model adoption, conformal layer, reconciliation method):
Tuning without measurement is worse than defaults.
npx claudepluginhub pvillega/claude-templates --plugin ctZero-shot univariate time series forecasting using Google's TimesFM foundation model. Supports CSV, DataFrame, and array inputs with point forecasts and prediction intervals. Includes a mandatory preflight system checker.
Forecasts univariate time series zero-shot using Google's TimesFM model. Supports CSV/DataFrame/array inputs with point forecasts and prediction intervals. Includes preflight system checker for RAM/GPU.
Zero-shot univariate time-series forecasting with Google's TimesFM foundation model. Produces point forecasts and prediction intervals from CSV/DataFrame/array inputs with a preflight system checker.