Time Series Analysis Cheat Sheet
Techniques for analyzing and forecasting time-indexed data, covering stationarity, decomposition, ARIMA modeling, and evaluation with statsmodels.
Stationarity & Decomposition
Test for stationarity and split into components.
import pandas as pdfrom statsmodels.tsa.stattools import adfullerfrom statsmodels.tsa.seasonal import seasonal_decomposets = pd.read_csv("sales.csv", index_col="date", parse_dates=True)["sales"]# Augmented Dickey-Fuller test for stationarityresult = adfuller(ts)print(f"ADF statistic: {result[0]:.3f}, p-value: {result[1]:.4f}")# p < 0.05 -> reject null -> series is stationary# Decompose into trend, seasonal, and residual componentsdecomposition = seasonal_decompose(ts, model="additive", period=12)decomposition.plot()# Differencing to achieve stationarityts_diff = ts.diff().dropna()
ARIMA Forecasting
Fit an ARIMA model and forecast future values.
from statsmodels.tsa.arima.model import ARIMAimport matplotlib.pyplot as plt# ARIMA(p, d, q): p=AR order, d=differencing, q=MA ordermodel = ARIMA(ts, order=(2, 1, 2))fitted = model.fit()print(fitted.summary())# Forecast the next 12 periodsforecast = fitted.get_forecast(steps=12)mean_forecast = forecast.predicted_meanconf_int = forecast.conf_int()plt.plot(ts, label="observed")plt.plot(mean_forecast, label="forecast")plt.fill_between(conf_int.index, conf_int.iloc[:, 0], conf_int.iloc[:, 1], alpha=0.2)plt.legend()
Time Series Concepts
Core vocabulary for sequential data analysis.
- Stationarity- statistical properties (mean, variance) don't change over time; required by many models like ARIMA
- Trend- long-term increase or decrease in the series
- Seasonality- repeating pattern at fixed, known intervals (e.g. daily, yearly)
- Autocorrelation (ACF)- correlation of the series with its own lagged values
- Partial autocorrelation (PACF)- correlation with a lag after removing effects of shorter lags; used to choose AR order
- Differencing- subtracting consecutive observations to remove trend and induce stationarity
- ARIMA(p,d,q)- AutoRegressive Integrated Moving Average model combining lag terms, differencing, and error terms
- Exponential smoothing- forecasting method weighting recent observations more heavily (e.g. Holt-Winters)
Forecast Evaluation Metrics
Ways to score forecast accuracy.
- MAE- Mean Absolute Error; average absolute difference between forecast and actual
- RMSE- Root Mean Squared Error; penalizes large errors more than MAE
- MAPE- Mean Absolute Percentage Error; scale-independent, but unstable near zero actuals
- Walk-forward validation- retrain and re-evaluate on an expanding window to mimic real forecasting
- Baseline comparison- always compare against a naive forecast (e.g. last value or seasonal naive)
SARIMA & Grid Search Order Selection
Extend ARIMA with a seasonal component and pick orders systematically.
import itertoolsimport numpy as npfrom statsmodels.tsa.statespace.sarimax import SARIMAX# SARIMA(p,d,q)(P,D,Q,s): seasonal terms capture repeating patterns (e.g. s=12 for monthly)model = SARIMAX( ts, order=(1, 1, 1), seasonal_order=(1, 1, 1, 12), enforce_stationarity=False, enforce_invertibility=False,)fitted = model.fit(disp=False)# Grid search over (p,d,q) using AIC as the selection criterionbest_aic, best_order = np.inf, Nonefor p, d, q in itertools.product(range(3), range(2), range(3)): try: candidate = SARIMAX(ts, order=(p, d, q), seasonal_order=(1, 1, 1, 12)).fit(disp=False) if candidate.aic < best_aic: best_aic, best_order = candidate.aic, (p, d, q) except Exception: continueprint(f"Best order: {best_order}, AIC: {best_aic:.2f}")
Forecasting with Prophet
Fit an additive trend+seasonality model that handles holidays and missing data gracefully.
from prophet import Prophet# Prophet expects columns named 'ds' (date) and 'y' (value)df = ts.reset_index().rename(columns={"date": "ds", "sales": "y"})m = Prophet( yearly_seasonality=True, weekly_seasonality=False, changepoint_prior_scale=0.05, # higher = more flexible trend)m.add_country_holidays(country_name="US")m.fit(df)future = m.make_future_dataframe(periods=90)forecast = m.predict(future)# yhat, yhat_lower, yhat_upper give the point forecast and uncertainty intervalfig = m.plot(forecast)fig2 = m.plot_components(forecast) # trend, weekly, yearly breakdown
Lag & Rolling Feature Engineering for ML Forecasters
Turn a time series into a supervised learning table for tree-based models.
import pandas as pddef make_features(df, target_col, lags=(1, 7, 14), windows=(7, 30)): out = df.copy() for lag in lags: out[f"lag_{lag}"] = out[target_col].shift(lag) for w in windows: out[f"roll_mean_{w}"] = out[target_col].shift(1).rolling(w).mean() out[f"roll_std_{w}"] = out[target_col].shift(1).rolling(w).std() out["dow"] = out.index.dayofweek out["month"] = out.index.month out["is_weekend"] = out["dow"].isin([5, 6]).astype(int) return out.dropna()features = make_features(ts.to_frame("sales"), "sales")# Feed into LightGBM/XGBoost with a TimeSeriesSplit — never a random split
Granger Causality & Multivariate VAR
Test whether one series helps predict another, then jointly model several series.
from statsmodels.tsa.stattools import grangercausalitytestsfrom statsmodels.tsa.api import VAR# Does 'marketing_spend' Granger-cause 'sales'? (predictive precedence, not true causality)data = pd.concat([ts, marketing_spend], axis=1).dropna()results = grangercausalitytests(data[["sales", "marketing_spend"]], maxlag=4)# VAR models multiple interdependent series jointlyvar_model = VAR(data)lag_order = var_model.select_order(maxlags=10) # AIC/BIC-based lag selectionfitted_var = var_model.fit(lag_order.aic)forecast = fitted_var.forecast(data.values[-fitted_var.k_ar:], steps=12)
Advanced Time Series Concepts
Vocabulary beyond basic ARIMA that shows up in production forecasting work.
- Heteroskedasticity- non-constant variance over time; addressed with GARCH models or log/Box-Cox transforms
- GARCH- Generalized AutoRegressive Conditional Heteroskedasticity; models time-varying volatility, common in finance
- Cointegration- two non-stationary series that share a stable long-run relationship, tested via Engle-Granger or Johansen tests
- Backtesting window- rolling or expanding evaluation windows that simulate how a forecaster would have performed historically
- Structural break- a sudden shift in a series' underlying process (e.g. regime change) that invalidates models fit on earlier data
- Exogenous regressors (SARIMAX)- external predictor variables added to a time series model alongside its own lags
- Change point detection- identifying timestamps where the statistical properties of a series shift abruptly (e.g. ruptures, PELT)
- Prediction interval vs confidence interval- prediction intervals quantify uncertainty in a single future observation; confidence intervals quantify uncertainty in an estimated parameter
Never randomly shuffle or use standard k-fold cross-validation on time series data — always evaluate with a forward-chaining/expanding-window split (e.g. TimeSeriesSplit) so the model is never trained on future data to predict the past.