Skip to content
  • Time-Series Basics · Machine Learning

Time-Series Basics

LearnViaNotes @learnvianotes· 3 min read

A time series is a sequence of observations in time order — sales per day, CPU load per minute. Order matters: neighbouring values are correlated, the future must never leak into the past, and a simple “same as last week” baseline is surprisingly hard to beat.

ComponentMeaningExample
TrendLong-term increase or decreaseGrowing user base
SeasonalityRepeating pattern with a fixed periodWeekly shopping cycle, yearly peaks
CyclesRises and falls without a fixed periodBusiness cycles
NoiseIrregular variationRandom day-to-day fluctuation

A forecasting example

Daily demand with a trend, a weekly pattern and noise. Forecast the last 28 days using only information available the day before:

Python
import numpy as np
import pandas as pd
from sklearn.linear_model import Ridge
from sklearn.metrics import mean_absolute_error

rng = np.random.default_rng(0)
days = pd.date_range("2024-01-01", periods=364, freq="D")
t = np.arange(364)
weekly = np.array([0, 2, 3, 3, 5, 12, 9])[days.dayofweek]          # busier on weekends
y = pd.Series(50 + 0.05 * t + weekly + rng.normal(0, 2, 364), index=days)

print(round(y.autocorr(lag=1), 2), round(y.autocorr(lag=7), 2))     # 0.68 0.91 ← strong weekly autocorrelation

df = pd.DataFrame({"y": y})
df["lag_1"] = y.shift(1)                                  # yesterday
df["lag_7"] = y.shift(7)                                  # same weekday last week
df["roll_7"] = y.shift(1).rolling(7).mean()               # past week's mean — shift FIRST, then roll
df["dow"] = df.index.dayofweek
df = pd.get_dummies(df, columns=["dow"], dtype=float).dropna()

train, test = df.iloc[:-28], df.iloc[-28:]                 # split by time, never shuffle
X_cols = [c for c in df.columns if c != "y"]
model = Ridge(alpha=1.0).fit(train[X_cols], train["y"])

print(round(mean_absolute_error(test["y"], test["lag_1"]), 2))                 # 5.18 ← naive: tomorrow = today
print(round(mean_absolute_error(test["y"], test["lag_7"]), 2))                 # 2.51 ← seasonal naive: = last week
print(round(mean_absolute_error(test["y"], model.predict(test[X_cols])), 2))   # 1.99 ← model with lag + calendar features

Approaches

FamilyExamplesGood for
BaselinesNaive, seasonal naive, moving averageAlways — the bar to beat
Classical statisticalExponential smoothing (ETS, Holt-Winters), ARIMA/SARIMA (statsmodels)Single series, clear trend/seasonality, small data, prediction intervals
ML on engineered featuresLags, rolling stats, calendar and holiday features + gradient boosting / linear modelsMany related series, external drivers (price, promotions, weather)
Deep learningRNN/LSTM, temporal CNNs, transformers (see Deep Learning)Very many long series, complex patterns

Practical points

  • Multi-step horizons: recursive (feed predictions back as lags) accumulates errors; direct (one model per horizon) avoids that at more cost.

  • Metrics: MAE/RMSE per horizon; MASE = MAE ÷ MAE of the seasonal-naive forecast (below 1 beats the baseline); avoid MAPE with values near 0.

  • Validation: rolling-origin (expanding window) evaluation mirrors how forecasts are produced in production.

  • Label availability: if yesterday's sales are only final two days later, lag_1 isn't available at prediction time — use a gap.

  • Report prediction intervals, not only point forecasts — inventory and staffing decisions depend on the uncertainty.

How is validating a time-series model different?

What is stationarity and why does it matter?

What baseline would you use for a forecasting problem?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report