Time Series Fundamentals
A time series is values in time order. Tomorrow depends on today, so shuffling breaks it and forecasting means reading that dependence.
Why Does This Exist?
Standard models assume rows are independent. Time data breaks that promise. Tomorrow temperature leans on today. Next quarter sales repeat last quarter rhythm. Train a plain classifier on shuffled weeks and it scores well in the notebook, then fails live because you let it peek at the future and hid the dependence it needed.
You need a different starting point: order first, dependence second, components third. That means splitting chronologically, measuring how past lags predict the present, and naming which part moves.
This page builds that base: what a series is, its four parts, autocorrelation, and steadiness. The calendar part in depth lives in seasonality and trends. Testing steadiness lives in stationarity testing. Measuring lag dependence lives in autocorrelation. Splitting safely lives in cross-validation. Where deep models take over lives in transformer forecasting.
Basics first: means the value at time , and lag means steps back, so is last week. Everything below uses those two.
Think of It Like This
Reading footprints on a beach
You find footprints in wet sand. Each print points to the next, stride by stride. You can tell direction, pace, and where the walker stumbled. Scoop the sand, stir it, and lay it flat again and every print survives but the story dies. Same grains, no walk.
A time series is that beach before stirring. Order is the signal. Shuffle it and you keep every number while losing direction, rhythm, and momentum.
Where it stops: footprints fade and the tide resets the beach. Data keeps every past value perfectly, so old regimes linger in the numbers long after the world moved on. You must cut history yourself.
How It Actually Works
A series mixes four ingredients. Trend is the slow direction, up or flat. Season is the fixed-period bounce, like weekly or yearly. Cycle is the slow wobble with no fixed period, like business booms. Noise is the leftover hash with mean near zero. Additive form says . When swings grow with level, multiplicative form says .
Dependence is measured by autocorrelation. Lag correlation asks how well steps back predicts now. Weekly rhythm spikes at . Trend keeps high across many lags. The plot of over is the correlogram, your first diagnostic.
Steadiness is stationarity in brief: mean fixed so , spread fixed, and blind to clock time. Most classical tools need it. Straight trends yield to . Fixed seasons yield to . Growing spread yields to .
Worked example
Four weeks of signups: 10, 12, 14, 16. Mean is .
- First-half mean is .
- Second-half mean is .
- The mean drifts 11 to 15, so levels are not steady despite one tidy average of 13.
Differences are 2, 2, 2, with mean 2 and spread 0. Lag 1 pairs are (10, 12), (12, 14), (14, 16), rising in lockstep with correlation 1.0. Order tells you everything here: next week points to 18 by trend, while the shuffled set 16, 10, 14, 12 points nowhere.
Code
This stdlib snippet reproduces the diagram numbers: half means that drift, flat differences, and perfect lag 1 linkage:
def mean(xs: list[float]) -> float: return sum(xs) / len(xs)
def lag_pairs(xs: list[float], k: int) -> list[tuple[float, float]]: """Pairs of (past, present) k steps apart.""" return [(xs[i], xs[i + k]) for i in range(len(xs) - k)]
def lag1_corr(xs: list[float]) -> float: """Pearson correlation between xs[:-1] and xs[1:] without imports.""" pairs: list[tuple[float, float]] = lag_pairs(xs, 1) mx: float = mean([p[0] for p in pairs]) my: float = mean([p[1] for p in pairs]) num: float = sum((x - mx) * (y - my) for x, y in pairs) den: float = (sum((x - mx) ** 2 for x, _ in pairs) * sum((y - my) ** 2 for _, y in pairs)) ** 0.5 return num / den
sales: list[float] = [10.0, 12.0, 14.0, 16.0]print(mean(sales)) # -> 13.0print(mean(sales[:2])) # -> 11.0print(mean(sales[2:])) # -> 15.0print(lag1_corr(sales)) # -> 1.0Mean 13.0 hides the drift 11.0 to 15.0. Lag 1 correlation 1.0 proves the dependence shuffling would destroy. Split chronologically and the model can learn it.
Watch Out For
Shuffling time into a random split
You call a random splitter out of habit. The symptom is a model that shines offline and flops live: training saw next month while validating this month, so it memorised the future. Leakage looks like skill until deployment.
Fix it by splitting on time, always. Train on early weeks, validate on later weeks, as cross-validation demands. If your splitter shuffles, it is the wrong splitter.
Modelling drift as if steady
You fit a steady-mean tool to climbing data without a test. The symptom is intervals that start snug and end lost: the live mean walks out of the training band while errors grow one-sided.
Fix it by checking half means and running stationarity testing before you fit. Drifted halves mean difference or detrend first, then model.
The Quick Version
- A time series is values in time order, and order is the signal.
- Four parts mix in every point: trend, fixed season, loose cycle, and noise.
- Ten 12 14 16 averages 13 while halves sit at 11 and 15, so one mean hides drift.
- Differences of 2 2 2 stay flat with spread 0 when levels wander.
- Lag 1 correlation 1.0 proves this week predicts next week.
- Split on time, never shuffled, or future leaks into training.