12 · Lag features
The sliding-window trick turns a 1-D series into a supervised (X, y) table of past-vs-present rows — and that single reshape lets any regressor forecast.
Building columns lag_1..lag_k with .shift() reframes forecasting as ordinary supervised learning: each row is (recent past → next value). Now a random forest, gradient boosting, or linear model can forecast — no ARIMA required.
Without this:
Without lag features your series is a single column no regressor can learn from; the sliding window is the bridge that connects classical time series to the entire scikit-learn toolbox.
So far we've forecast with models built for time (ARIMA, Holt-Winters). But there's a second, enormously powerful path: reshape the series into a supervised table and hand it to any regressor — random forest, gradient boosting, linear regression. The trick that makes this possible is lag features.
A lag of order k is simply the value k steps in the past. In pandas, series.shift(k) slides every value down by k rows, so the column lag_1 on row t holds y[t-1], lag_2 holds y[t-2], and so on. Line up several lag columns next to the current value and you've built a sliding window:
| target (yₜ) | lag_1 | lag_2 | lag_3 | |---|---|---|---| | yₜ | yₜ₋₁ | yₜ₋₂ | yₜ₋₃ |
Each row now says "given the last 3 values, the next value was yₜ." That is exactly the (X, y) shape scikit-learn expects: X is the lag columns, y is the target. The model learns the mapping from recent past to next step.
Two practical details. First, the earliest rows have NaN lags — there's no "value 3 days before day 0" — so you dropna() to discard that warm-up. Second, you must build lags in time order and never shuffle: the lag columns are how order enters an otherwise order-blind regressor. Below we take a series, build lag_1..lag_3, drop the warm-up, and inspect the supervised frame.
Python (in browser)
.shift(k) builds lag columns; dropna() trims the warm-up; the result is a clean (X, y) supervised table any regressor can fit.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
In a lag-feature DataFrame built with shift(), why do the very first rows contain NaN, and what do you do about them?
- A lag of order k is the value k steps in the past; series.shift(k) builds the lag_k column.
- Stacking lag_1..lag_k beside the current value reshapes a 1-D series into a supervised (X, y) table any regressor can fit.
- The first k rows have NaN lags (no full window) — dropna() the warm-up, and never shuffle the order.
Lag features power every gradient-boosting forecaster (LightGBM/XGBoost on tabular time series) and are the input layer of many demand-forecasting Kaggle winners.
If you remove it: Without lag features a regressor sees only the current row and has no memory of the past — it cannot exploit autocorrelation, the entire forecasting signal.