Skip to content
AI360XpertBeta

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.

Ten 12 14 16 averages 13 while halves sit at 11 and 15, so order carries signal that shuffling destroys
Ten 12 14 16 averages 13 while halves sit at 11 and 15, so order carries signal that shuffling destroys

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: yty_t means the value at time tt, and lag kk means kk steps back, so yt−1y_{t-1} 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 yty_t mixes four ingredients. Trend TtT_t is the slow direction, up or flat. Season StS_t is the fixed-period bounce, like weekly or yearly. Cycle CtC_t is the slow wobble with no fixed period, like business booms. Noise εt\varepsilon_t is the leftover hash with mean near zero. Additive form says yt=Tt+St+Ct+εty_t = T_t + S_t + C_t + \varepsilon_t. When swings grow with level, multiplicative form says yt=Tt×St×Ct×εty_t = T_t \times S_t \times C_t \times \varepsilon_t.

Dependence is measured by autocorrelation. Lag kk correlation ρk=Corr(yt,yt−k)\rho_k = \text{Corr}(y_t, y_{t-k}) asks how well kk steps back predicts now. Weekly rhythm spikes at ρ7\rho_7. Trend keeps ρ1\rho_1 high across many lags. The plot of ρk\rho_k over kk is the correlogram, your first diagnostic.

Steadiness is stationarity in brief: mean μ\mu fixed so E[yt]=μ\mathbb{E}[y_t] = \mu, spread σ2\sigma^2 fixed, and ρk\rho_k blind to clock time. Most classical tools need it. Straight trends yield to Δyt=yt−yt−1\Delta y_t = y_t - y_{t-1}. Fixed seasons yield to yt−yt−my_t - y_{t-m}. Growing spread yields to log⁡(yt)\log(y_t).

Worked example

Four weeks of signups: 10, 12, 14, 16. Mean is (10+12+14+16)/4=52/4=13(10 + 12 + 14 + 16) / 4 = 52 / 4 = 13.

  • First-half mean is (10+12)/2=22/2=11(10 + 12) / 2 = 22 / 2 = 11.
  • Second-half mean is (14+16)/2=30/2=15(14 + 16) / 2 = 30 / 2 = 15.
  • 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.0

Mean 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.