Time Series Forecasting
Stationarity and the ADF test, ACF/PACF, rolling-origin backtesting, GBDT vs ARIMA, multi-step forecasting, seasonality and intermittent demand.
11 questions
JuniorTheoryVery commonWhat separates additive from multiplicative seasonality, and how do you encode it for a GBDT?
What separates additive from multiplicative seasonality, and how do you encode it for a GBDT?
Additive seasonality adds a fixed amount each period; multiplicative scales with the level, so swings grow with the series and a log makes it additive. For a GBDT, encode calendar position — day-of-week, Fourier terms of the year, holiday flags.
Common mistakes
- ✗Feeding a raw timestamp to a tree and expecting it to learn the weekly cycle
- ✗Fitting additive seasonality to a series whose swings grow with its level
- ✗Encoding the day of year as one high-cardinality category instead of smooth terms
Follow-up questions
- →Why do Fourier terms beat one dummy variable per day of the year?
- →How do you encode a moving holiday such as Easter?
JuniorTheoryVery commonWhat do gradient boosting on lag features, ARIMA and the library Prophet each assume about a series?
What do gradient boosting on lag features, ARIMA and the library Prophet each assume about a series?
ARIMA assumes one stationary series with linear autocorrelation. Prophet fits an additive trend plus seasonality and holidays and tolerates gaps. GBDT on lag features handles nonlinearity across many series, but cannot extrapolate a trend.
Common mistakes
- ✗Expecting a tree model to extrapolate a trend past the range it saw in training
- ✗Fitting ARIMA per series on a hundred thousand SKUs and calling it a baseline
- ✗Treating Prophet as a general model rather than a curve-fitting decomposition
Follow-up questions
- →What features must you add so a GBDT can cope with a growing trend?
- →When is a per-series classical model still the right call?
JuniorTheoryCommonIn the Augmented Dickey-Fuller (ADF) test, what is the null and what does failing to reject prove?
In the Augmented Dickey-Fuller (ADF) test, what is the null and what does failing to reject prove?
The null is that the series has a unit root and so is non-stationary; a small p-value rejects it and supports stationarity. Failing to reject proves nothing — it found no evidence against a unit root, and power is low on short series.
Common mistakes
- ✗Reading a large p-value as proof that the series is stationary
- ✗Ignoring how weak the test's power is on a few hundred observations
- ✗Running ADF on a strongly seasonal series without a seasonal difference first
Follow-up questions
- →How does the KPSS stationarity test complement ADF, given its opposite null?
- →What do you conclude when ADF and KPSS disagree on the same series?
JuniorTheoryCommonWhat is stationarity, and what do differencing and a log transform each fix?
What is stationarity, and what do differencing and a log transform each fix?
A stationary series keeps mean, variance and autocovariance constant over time — exactly what ARIMA assumes. Differencing removes a trend or unit root and stabilises the mean; a log transform tames variance that grows with the level.
Common mistakes
- ✗Calling a series with a stable mean but growing variance stationary
- ✗Differencing twice by reflex, which over-differences and injects noise
- ✗Expecting a log transform to remove a trend rather than stabilise variance
Follow-up questions
- →How do you tell over-differencing from a genuinely non-stationary series?
- →When would you difference at the seasonal lag instead of at lag one?
MiddleDebuggingCommonA forecast looks excellent but may just repeat yesterday's value — how do you catch that?
A forecast looks excellent but may just repeat yesterday's value — how do you catch that?
Cross-correlate forecast against actuals — a peak at lag one means it copies yesterday. Score it against naive and seasonal-naive baselines with MASE, because on a near random walk MAPE looks small; beating seasonal naive is the proof.
Open full question →Common mistakes
- ✗Judging a forecast without ever fitting a naive baseline to compare it against
- ✗Trusting a small MAPE on a slow-moving series that a lag-one copy also achieves
- ✗Reporting MAPE on a series with near-zero actuals, where it explodes
Follow-up questions
- →Why does MAPE blow up as actuals approach zero, and what replaces it?
- →Which baseline do you pick for a series with strong weekly seasonality?
MiddleTheoryCommonWhich obvious time-series features quietly leak the future, and how do you build them safely?
Which obvious time-series features quietly leak the future, and how do you build them safely?
Centred rolling means, aggregates over the whole history and imputation fitted across the split all pull future values into a training row. Make every window backward-looking and shifted by one step, and fit imputers inside each backtest fold.
Common mistakes
- ✗Using a centred window, which averages values recorded after the timestamp
- ✗Fitting scalers or imputers on the full history before the backtest split
- ✗Forgetting the one-step shift, so a row silently includes its own target
Follow-up questions
- →How long an embargo do you need when the label matures a week later?
- →How would you catch such a leak automatically inside a feature pipeline?
SeniorTheoryCommonRecursive, direct or multi-output multi-step forecasting — how does error compound in each?
Recursive, direct or multi-output multi-step forecasting — how does error compound in each?
Recursive feeds its prediction back as input, so error compounds with the horizon, though one model covers every step. Direct trains a model per horizon — no compounding, h times the cost. At horizon 30 direct or multi-output usually wins.
Common mistakes
- ✗Assuming a strong one-step score carries over to horizon thirty
- ✗Ignoring that recursive forecasting feeds its own noisy prediction back in
- ✗Overlooking the h-fold training and serving cost of the direct strategy
Follow-up questions
- →How do you keep a direct model's forecasts consistent across neighbouring horizons?
- →Why must the backtest score be reported per horizon rather than pooled?
JuniorTheoryOccasionalWhy is plain k-fold cross-validation illegal on a time series, and what replaces it?
Why is plain k-fold cross-validation illegal on a time series, and what replaces it?
Random k-fold puts future rows into the train fold, so the model learns from the future and the score is inflated. Rolling-origin backtesting replaces it — train up to a cut-off, test the next window, then move the cut-off forward and repeat.
Common mistakes
- ✗Shuffling rows before splitting a time-ordered dataset
- ✗Reporting a k-fold score for a model that will forecast forward in production
- ✗Keeping one fixed test window instead of moving the origin forward
Follow-up questions
- →When would you prefer a sliding window over an expanding one?
- →Why add an embargo gap between the train cut-off and the test window?
SeniorTheoryOccasionalHow do you read ARIMA orders p and q off the autocorrelation (ACF) and partial (PACF) plots, and when is that unreliable?
How do you read ARIMA orders p and q off the autocorrelation (ACF) and partial (PACF) plots, and when is that unreliable?
On a differenced series, a PACF cutting off after lag p with a decaying ACF means AR(p); an ACF cutting off after lag q with a decaying PACF means MA(q). It fails on mixed ARMA, on seasonal or still non-stationary data, and on short samples.
Common mistakes
- ✗Reading the plots before differencing, so the trend dominates every lag
- ✗Swapping the roles, taking p from the ACF and q from the PACF
- ✗Trusting a clean cut-off on a mixed ARMA, where neither plot cuts off
Follow-up questions
- →Which criterion do you fall back on when both plots simply decay?
- →How does a seasonal spike at lag twelve change the model you fit?
SeniorTheoryOccasionalA promo or a shock breaks the regime — how do you detect drift in a forecasting model and react?
A promo or a shock breaks the regime — how do you detect drift in a forecasting model and react?
Track rolling forecast error against its backtest band, watch residuals for sustained bias, and run a change-point test on the inputs. Once confirmed, retrain on a shorter recent window, add event features, and keep a naive fallback.
Common mistakes
- ✗Waiting for a scheduled retrain instead of monitoring the error in flight
- ✗Reacting to one bad day rather than a sustained shift in residual bias
- ✗Retraining on the whole history, which dilutes the new regime
Follow-up questions
- →How do you separate a one-off shock from a permanent regime change?
- →What guardrail stops a freshly retrained model from shipping worse forecasts?
SeniorDesignRareYou must forecast weekly demand for 100 000 SKUs across 40 warehouses for a retailer. Most SKU-warehouse pairs sell nothing in a given week, and the median non-zero sale is 2 units, while a few hundred pairs carry most of the revenue. The forecasts feed a replenishment system that orders 4 weeks ahead, and the whole grid must be refreshed nightly inside a 2-hour window. History covers 3 years and includes promotions and public holidays. Describe the model or models you would use, the loss you would optimise, the level at which you would aggregate, and how you would evaluate the result so the replenishment team can trust it.
You must forecast weekly demand for 100 000 SKUs across 40 warehouses for a retailer. Most SKU-warehouse pairs sell nothing in a given week, and the median non-zero sale is 2 units, while a few hundred pairs carry most of the revenue. The forecasts feed a replenishment system that orders 4 weeks ahead, and the whole grid must be refreshed nightly inside a 2-hour window. History covers 3 years and includes promotions and public holidays. Describe the model or models you would use, the loss you would optimise, the level at which you would aggregate, and how you would evaluate the result so the replenishment team can trust it.
Train one global GBDT over all pairs with lag, calendar and promo features, not 100k local models, under a Tweedie loss for the zero-inflated target. Aggregate the sparsest pairs upward and backtest rolling-origin with MASE against seasonal naive.
Common mistakes
- ✗Fitting one classical model per series when there are a hundred thousand of them
- ✗Optimising squared error on a target that is zero in most weeks
- ✗Reporting MAPE where most actuals are zero, so the metric is undefined
Follow-up questions
- →How would you turn a point forecast into a service-level order quantity?
- →What would make you fall back to a local model for the top revenue pairs?