Time Series Cheat Sheet — ARIMA, LSTM, Stationarity, ACF, Forecasting | Dataplexa
← Back to Cheat Sheets
Sheet icon

Time Series Cheat Sheet

ARIMA · SARIMA · LSTM · stationarity · ACF/PACF · lag features · decomposition · forecasting

Sheet 3 of 4 Specialized ML Intermediate Printable

Time Series Fundamentals

Core Concepts

A time series is a sequence of observations indexed in chronological order. Understanding its components is the first step before any modelling.

Additive Decomposition
Yt = Tt + St + Rt
T = Trend, S = Seasonality, R = Residual. Use additive when seasonal variation is constant over time.
Multiplicative Decomposition
Yt = Tt × St × Rt
Use multiplicative when seasonal variation grows with the trend level (e.g. retail sales, stock prices). Log-transform converts multiplicative → additive.
ComponentDescriptionExample
TrendLong-run increase or decreasePopulation growth
SeasonalityFixed-period repeating patternHoliday sales spike
CyclicalIrregular multi-year wavesEconomic boom/bust
ResidualRandom noise after decompositionWeather anomalies
IrregularOne-off shocksPandemic, earthquake
STL Decomposition (statsmodels)
from statsmodels.tsa.seasonal import STL

stl = STL(series, period=12).fit()
stl.trend      # trend component
stl.seasonal   # seasonal component
stl.resid      # residuals
stl.plot()     # 4-panel decomposition
TermMeaning
Lag kValue at time t−k
Differencing∇Yt = Yt − Yt−1
Rolling meanMoving average over window w
AutocorrelationCorr(Yt, Yt−k)
White noiseiid, zero mean, constant var
Random walkYt = Yt−1 + εt
Always plot first: Before any modelling, visualise the raw series, rolling mean, and rolling std. Patterns (trend, seasonality, outliers) are usually visible to the eye before any test confirms them.

Stationarity

ADF · KPSS Tests

A stationary series has constant mean, variance, and autocovariance over time. Required by ARIMA and most classical models.

Strict Stationarity Conditions
E[Yt] = μ  ·  Var(Yt) = σ²  ·  Cov(Yt, Yt−k) = f(k)
Mean and variance are constant. Covariance depends only on lag k, not on time t. Also called "weak" or "covariance" stationarity.
ADF & KPSS Tests
from statsmodels.tsa.stattools import adfuller, kpss

# ADF: H0 = unit root (non-stationary)
adf, p, _, _, _, _ = adfuller(series)
print(f"ADF p={p:.4f}")
# p < 0.05 → reject H0 → stationary ✓

# KPSS: H0 = stationary
stat, p, _, _ = kpss(series, regression='c')
print(f"KPSS p={p:.4f}")
# p > 0.05 → fail to reject H0 → stationary ✓

# Make stationary: 1st difference
diff1 = series.diff().dropna()
ADF p-valueKPSS p-valueConclusion
< 0.05> 0.05Stationary ✓
> 0.05< 0.05Non-stationary → difference
< 0.05< 0.05Trend-stationary
> 0.05> 0.05Ambiguous → inspect plot

ACF & PACF

Autocorrelation
Autocorrelation Function (ACF)
ACF(k) = Corr(Yt, Yt−k) = γk / γ0
Total correlation between Yt and Yt−k including indirect paths via intermediate lags. Use to identify MA(q) order.
Partial Autocorrelation (PACF)
PACF(k) = Corr(Yt, Yt−k | Yt−1,…,Yt−k+1)
Direct correlation after removing effects of shorter lags. Use to identify AR(p) order.
PatternACFPACFModel
AR(p)Tails off slowlyCuts off after lag pARIMA(p,d,0)
MA(q)Cuts off after lag qTails off slowlyARIMA(0,d,q)
ARMA(p,q)Tails offTails offARIMA(p,d,q)
White noiseAll within ±1.96/√nAll within bandsNo model needed
Plot ACF & PACF
from statsmodels.graphics.tsaplots import (
  plot_acf, plot_pacf)
import matplotlib.pyplot as plt

fig, (ax1, ax2) = plt.subplots(2, 1)
plot_acf(series, lags=40, ax=ax1)
plot_pacf(series, lags=40, ax=ax2)
plt.tight_layout()

ARIMA & SARIMA

Classical Forecasting
ARIMA(p, d, q) Model
ΔᵈYt = c + ΣφiYt−i + Σθjεt−j + εt
p = AR order (PACF cuts off), d = differencing order (for stationarity), q = MA order (ACF cuts off). εt = white noise error.
SARIMA(p,d,q)(P,D,Q)[m]
ARIMA × Seasonal ARIMA at period m
P, D, Q = seasonal AR, differencing, MA orders. m = seasonal period (12=monthly, 4=quarterly, 7=daily-weekly). Handles recurring seasonal patterns.
ParameterMeaningHow to choose
pAR lagsPACF cutoff
dDifferencesADF test (usually 0–2)
qMA lagsACF cutoff
P,D,QSeasonal ordersSeasonal ACF/PACF
mSeason periodDomain knowledge
ARIMA / SARIMA (statsmodels)
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.statespace.sarimax import SARIMAX

# ARIMA(1,1,1)
model = ARIMA(train, order=(1,1,1))
fit = model.fit()
print(fit.summary())

# Forecast 12 steps ahead
fc = fit.forecast(steps=12)

# SARIMA(1,1,1)(1,1,1,12)
model = SARIMAX(train,
  order=(1,1,1),
  seasonal_order=(1,1,1,12))
fit = model.fit(disp=False)

# Auto-select orders: pmdarima
from pmdarima import auto_arima
model = auto_arima(train,
  seasonal=True, m=12,
  information_criterion='aic',
  stepwise=True)
Model CheckGood Sign
Residual ACFAll lags within ±1.96/√n bands
Ljung-Box testp > 0.05 (no autocorrelation)
AIC/BICLower is better across models
Residual dist.Approx. normal, zero mean
Model Diagnostics
# Residual diagnostics
fit.plot_diagnostics()

# Ljung-Box test
from statsmodels.stats.diagnostic import acorr_ljungbox
lb = acorr_ljungbox(fit.resid, lags=[10])
# p > 0.05 → residuals are white noise ✓
AIC vs BIC: AIC favours more complex models (lower penalty). BIC penalises complexity more — better for short series. Use AIC for forecasting, BIC for model selection.

Lag Features & Feature Engineering

ML Approach

Convert a time series into a supervised ML problem by engineering features from past observations.

Creating Lag & Rolling Features (pandas)
import pandas as pd

df['lag_1']  = df['value'].shift(1)
df['lag_7']  = df['value'].shift(7)
df['lag_30'] = df['value'].shift(30)

# Rolling statistics
df['roll_mean_7'] = (
  df['value'].rolling(7).mean())
df['roll_std_7']  = (
  df['value'].rolling(7).std())
df['ewm_7'] = (
  df['value'].ewm(span=7).mean())

# Calendar features
df['hour']       = df.index.hour
df['dayofweek']  = df.index.dayofweek
df['month']      = df.index.month
df['is_weekend'] = df.index.dayofweek >= 5
FeatureCaptures
lag_kDirect autocorrelation at lag k
rolling_meanLocal trend / smoothed level
rolling_stdLocal volatility / spread
ewmExponentially weighted trend
diffChange from previous step
CalendarDay/month/hour cyclical effects

LSTM for Time Series

Deep Learning
LSTM Gate Equations
ft = σ(Wf·[ht−1, xt] + bf)  ← forget gate
it = σ(Wi·[ht−1, xt] + bi)  ← input gate
Ct = ft⊙Ct−1 + it⊙tanh(Wc·[ht−1,xt]+bc)
ot = σ(Wo·[ht−1, xt] + bo)  ← output gate
ht = ot ⊙ tanh(Ct)
Ct = cell state (long-term memory). ht = hidden state (short-term). ⊙ = element-wise multiply. Forget gate decides what to erase from memory.
LSTM Forecasting (PyTorch)
import torch.nn as nn

class LSTMForecaster(nn.Module):
  def __init__(self, n_features,
               hidden=64, n_layers=2):
    super().__init__()
    self.lstm = nn.LSTM(
      n_features, hidden,
      num_layers=n_layers,
      batch_first=True,
      dropout=0.2)
    self.fc = nn.Linear(hidden, 1)

  def forward(self, x):
    out, _ = self.lstm(x)
    return self.fc(out[:, -1, :])
Input shape: LSTM expects [batch, seq_len, features]. Use a sliding window to create sequences. Typical seq_len = 30–90 days for daily data.

Forecasting Models Comparison

Model Selection Guide
ModelTypeHandles SeasonalityBest For
NaïveBaselineSeasonal naïveBenchmarking
Exponential SmoothingStatisticalHolt-Winters (triple)Smooth trends, fast
ARIMAStatisticalWith SARIMAStationary, univariate
ProphetDecompositionMultiple seasonalitiesBusiness data, holidays
XGBoostML (tabular)Via lag featuresMany features, tabular
LSTMDeep LearningLearned implicitlyLong sequences, multivariate
Temporal Fusion TransformerDeep LearningAttention-basedMulti-horizon, interpretable
N-BEATSDeep LearningExplicit blocksPure TS, no covariates
Prophet — Quick Forecast
from prophet import Prophet

# df must have columns: ds, y
m = Prophet(
  yearly_seasonality=True,
  weekly_seasonality=True,
  daily_seasonality=False,
  changepoint_prior_scale=0.05
)
m.add_country_holidays(country_name='US')
m.fit(df)

future = m.make_future_dataframe(
  periods=365)
forecast = m.predict(future)
m.plot(forecast)
m.plot_components(forecast)
When to use what: Start with Naïve + ETS baselines. Try ARIMA/SARIMA for univariate with clear patterns. Use Prophet for business data with holidays. Use LSTM/TFT when you have multivariate inputs or very long sequences (>1000 steps).

Train / Test Split

Validation Strategy

Never shuffle time series data. Always respect temporal order — future data must not leak into training.

Correct Time Series Split
# Simple chronological split
split = int(len(df) * 0.8)
train, test = df[:split], df[split:]

# Walk-forward cross-validation
from sklearn.model_selection import TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits=5)
for train_idx, test_idx in tscv.split(X):
  X_tr, X_te = X[train_idx], X[test_idx]
  # fit → predict → score each fold
StrategyWhenNotes
Hold-outQuick baselineLast 20% as test
Walk-forwardRobust evaluationExpanding window
Sliding windowFixed training sizeSame window size each fold
Purged k-foldOverlapping featuresGap between train/test folds
Data leakage: Computing rolling features on the full dataset before splitting leaks future information into training. Always compute rolling stats after the train/test split.

Forecasting Evaluation Metrics

MAE · RMSE · MAPE · SMAPE
Key Error Metrics
MAE = (1/n) Σ|yt − ŷt|
RMSE = √[(1/n) Σ(yt − ŷt)²]
MAPE = (100/n) Σ|yt−ŷt| / |yt|
SMAPE = (200/n) Σ|yt−ŷt| / (|yt|+|ŷt|)
MetricUnitUse WhenWeakness
MAESame as yInterpretable errorDoesn't penalise large errors
RMSESame as yLarge errors matter moreSensitive to outliers
MAPE%Comparing seriesUndefined when y=0
SMAPE%Symmetric % errorCan be misleading near 0
MASERelativeScale-free comparisonNeeds in-sample naïve MAE
Always compare to a naïve baseline: A naïve model (predict last value) or seasonal naïve (predict same period last year) sets the minimum bar. If your model doesn't beat naïve, it's not useful.

End-to-End Forecasting Pipeline

Workflow
  1. Load & inspect — parse datetime index, check frequency, plot raw series, identify gaps and outliers
  2. Clean — handle missing values (forward fill, interpolate, or model-based imputation), remove outliers
  3. Decompose — STL or classical decomposition to separate trend, seasonality, residual
  4. Stationarity test — ADF + KPSS tests. Difference until stationary (d=1 usually sufficient)
  5. ACF/PACF analysis — identify AR(p) and MA(q) orders for ARIMA, or choose lag window for ML
  6. Feature engineering — lag features, rolling stats, calendar variables, Fourier terms for seasonality
  7. Train / validate — walk-forward cross-validation, never shuffle, watch for leakage
  8. Model & tune — fit ARIMA/Prophet/LSTM, tune hyperparameters, compare against naïve baseline
  9. Evaluate — report MAE, RMSE, MAPE on hold-out test set; plot forecast vs actuals with CI
  10. Monitor — track residuals and retrain when distribution shifts (concept drift)
XGBoost on Lag Features
import xgboost as xgb
from sklearn.metrics import mean_absolute_error

# Build lag feature matrix
lags = [1, 7, 14, 30]
for lag in lags:
  df[f'lag_{lag}'] = df['y'].shift(lag)
df = df.dropna()

features = [f'lag_{l}' for l in lags]
X, y = df[features], df['y']
split = int(0.8 * len(df))
X_tr, X_te = X[:split], X[split:]
y_tr, y_te = y[:split], y[split:]

model = xgb.XGBRegressor(
  n_estimators=500, learning_rate=0.05,
  max_depth=5, subsample=0.8)
model.fit(X_tr, y_tr,
  eval_set=[(X_te, y_te)],
  early_stopping_rounds=50,
  verbose=False)
mae = mean_absolute_error(
  y_te, model.predict(X_te))
LibraryBest For
statsmodelsARIMA, SARIMA, ETS
pmdarimaauto_arima, order selection
prophetBusiness forecasting, holidays
sktimeUnified sklearn-style TS API
dartsLSTM, TFT, N-BEATS, ensembles
neuralforecastNHITS, PatchTST, TimesNet

Time Series Mastery Checklist

Self-Assessment

Foundations & Stationarity

  • Decompose a series into trend, seasonality, and residual using STL
  • Distinguish additive vs multiplicative decomposition
  • Run ADF and KPSS tests and interpret combined results
  • Apply first or seasonal differencing to achieve stationarity
  • Read an ACF plot to identify MA order
  • Read a PACF plot to identify AR order

ARIMA & Feature Engineering

  • Fit an ARIMA(p,d,q) and interpret the summary table
  • Extend to SARIMA with seasonal orders and period m
  • Use auto_arima to select orders automatically
  • Diagnose residuals with Ljung-Box test and ACF plot
  • Engineer lag, rolling mean, rolling std, and EWM features
  • Add calendar features (day of week, month, is_weekend)

ML Forecasting & Evaluation

  • Implement walk-forward cross-validation without data leakage
  • Build and train an LSTM forecaster with sliding window input
  • Set up a Prophet model with seasonality and holidays
  • Train XGBoost on lag features for time series regression
  • Calculate and compare MAE, RMSE, MAPE against naïve baseline
  • Choose the right library: statsmodels vs Prophet vs darts

Next up in Specialized ML → Sheet 4 covers Reinforcement Learning: reward functions, policies, Q-learning, Deep Q-Networks, policy gradients, and PPO.

4 · Reinforcement Learning Cheat Sheet →
← Back