Time Series Forecasting
Time series components, ACF and PACF analysis, univariate forecasting (AR, MA, ARMA, ARIMA, SARIMA, SARIMAX), multivariate forecasting (VARMA, VARMAX), and exponential smoothing.
Topics in this chapter
- Concept and Components of Time Series
- Autocorrelation Function (ACF) and Partial Autocorrelation Function (PACF)
- Correlogram, Plotting ACF and PACF
- Univariate Forecasting: AR, MA, ARMA, ARIMA, SARIMA, SARIMAX
- Multivariate Forecasting: VARMA, VARMAX
- Smoothing: Simple Exponential Smoothing, Holt-Winter's Exponential Smoothing
Time Series Components and Autocorrelation Function Analysis
Decomposing a Time Series: Trend, Seasonality, and Residuals
A time series is a sequence of observations recorded at equally spaced points in time. The first step in understanding such data is to separate the signal into interpretable components. The classical additive decomposition posits
where denotes the trend (the long-term, slowly varying direction), is the seasonal component (regular, calendar-driven fluctuations), and is the residual (or irregular) component that captures everything else. When the amplitude of seasonal swings grows with the level of the series, a multiplicative decomposition is more appropriate; the multiplicative form can be transformed to an additive one by taking logarithms.
Trend is typically estimated by smoothing the series, for example with a moving average of order :
The choice of determines how much high-frequency variability is removed. For economic data such as quarterly GDP, a four-quarter moving average eliminates seasonal fluctuations and yields a smooth estimate of the underlying growth path.
Seasonality captures repeating patterns within a fixed period — daily cycles, weekly patterns, or annual seasonality. After the trend is removed, seasonal factors can be estimated by averaging the de-trended values for each season (e.g., all Januaries in monthly data). The seasonal component is then normalized so that it sums to zero over a full cycle (additive) or averages to one (multiplicative).
The residual is defined as what remains after extracting trend and seasonality. Ideally, behaves like a stationary white-noise process — uncorrelated random shocks with constant variance. If the decomposition is adequate, the residuals should show no systematic pattern or temporal dependence. The presence of significant autocorrelation in signals that the model is misspecified.
From an economic standpoint, decomposition mirrors the way analysts think about macroeconomic indicators: policymakers care about the trend (potential output), the seasonal (holiday spending spikes), and the residual (unexpected shocks such as oil price disruptions). Isolating these components allows for more interpretable diagnostics and more defensible forecasts.
Autocorrelation: Measuring Linear Dependence Across Time
The autocorrelation function (ACF) quantifies how a series correlates with its own past values. For a weakly stationary process (constant mean, variance, and autocovariance depending only on lag), the autocovariance at lag is
and the theoretical autocorrelation at lag is
lies in and measures the linear dependence between two observations time steps apart. A value close to () indicates that if is above the mean, tends to be above (below) the mean by a proportional amount.
In practice we estimate from the sample. Let . The sample autocorrelation is
This is a biased but consistent estimator; the denominator uses all terms to guarantee that the sequence forms a positive-semi-definite autocorrelation matrix. Under the null hypothesis that the data are independent white noise, Bartlett's approximation gives for , yielding the familiar confidence bands at that appear on every correlogram.
Interpreting the ACF yields insight into the data-generating process:
- A slow, linear decay of the ACF often signals a non-stationary trend (a random walk has for all ).
- A damped sinusoidal decay suggests the presence of a stationary autoregressive component with complex roots, often associated with business-cycle or seasonal fluctuations.
- A sharp cutoff after lag , where is essentially zero for , points to a moving-average model of order , .
- A seasonal time series will exhibit large positive spikes at lags that are multiples of the seasonal period (12, 24, …), superimposed on the underlying pattern.
In financial economics, a significantly positive in daily returns would suggest short-term predictability — a finding with profound implications for market efficiency.
Partial Autocorrelation: Isolating Direct Effects
While the ACF at lag mixes direct and indirect influences (via intermediate lags), the partial autocorrelation function (PACF) isolates the direct linear relationship between and after controlling for . Formally, the partial autocorrelation at lag , denoted , is the last coefficient of a linear regression of on its most recent values:
Thus measures the additional contribution of when all lags 1 through are already in the model.
The theoretical PACF can be obtained by solving the Yule–Walker equations for successive autoregressive orders. In practice, the sample PACF is computed recursively via the Durbin–Levinson recursion:
with the intermediate coefficients updated as for .
Interpretation of the PACF complements that of the ACF:
| Model | ACF | PACF |
|---|---|---|
| Tails off (exponential/sinusoidal decay) | Cuts off after lag | |
| Cuts off after lag | Tails off | |
| Tails off | Tails off |
Visualizing ACF and PACF with Correlograms in Python
A correlogram is the paired visualization of the sample ACF and PACF as bar plots against lag, overlaid with the confidence envelope. The statsmodels library provides ready-made functions:
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
df = pd.read_csv("temp.csv", header=0, index_col=0, parse_dates=True)
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
plot_acf(df, lags=40, alpha=0.05, ax=axes[0])
plot_pacf(df, lags=40, alpha=0.05, ax=axes[1], method="ywm")
axes[0].set_title("ACF — Minimum Daily Temperature")
axes[1].set_title("PACF — Minimum Daily Temperature")
plt.tight_layout()
plt.show()
The lags argument controls the maximum horizon inspected, while alpha sets the confidence level (typically for bands). The method="ywm" flag requests Yule–Walker estimates with sample-mean adjustment, the standard choice for PACF computation. The Ljung–Box Q-statistic,
provides a joint test of the null that the first autocorrelations are simultaneously zero; rejection indicates that residual structure remains to be modeled.
Univariate Time Series Forecasting Models
Foundations: Stationarity and Identification Tools
Before modelling, we must confront the notion of stationarity. A time series is strictly stationary if its joint distribution is invariant under time shifts. In practice, we rely on weak stationarity: constant mean , constant variance , and covariance that depends only on the lag . Most classical linear models assume weak stationarity; non-stationary behaviour must be removed prior to modelling.
To test for a unit root, we employ the Augmented Dickey-Fuller (ADF) test. The null hypothesis : the series has a unit root (is non-stationary) versus the alternative : stationarity. A -value below rejects , indicating that no further differencing is required. If the -value exceeds the threshold, the series is differenced once, , and the test is reapplied.
Autoregressive (AR) Models
An autoregressive model of order , AR(), expresses the current observation as a linear combination of its previous values plus a white-noise shock:
where is a serially uncorrelated error term with zero mean and constant variance. Using the lag operator defined by , the AR() model can be compactly written as , where is the autoregressive polynomial.
The constant is related to the unconditional mean by . Stationarity requires that all roots of the characteristic equation lie outside the unit circle. For , this reduces to . The interpretation is intuitive: the impact of a shock decays geometrically as it propagates through future values.
Economic Intuition: In financial and macroeconomic contexts, AR models capture momentum and persistence. An AR(1) model with implies that a positive shock to GDP growth will positively influence subsequent quarters, reflecting the inertia in economic expansion.
Moving Average (MA) Models
It is crucial to distinguish a Moving Average (MA) model from the simple moving average smoothing technique used in descriptive analytics. An MA model of order asserts that the current observation is a linear combination of the current and past white noise error terms:
where is the mean of the series and are the moving average parameters. In lag operator notation, this is , with .
Economic Intuition: MA models represent the lingering effects of transient, unobserved shocks. An MA(1) process implies that an unexpected policy change or market shock () affects the current period but completely dissipates by period . This "finite memory" of shocks is highly applicable in modeling inventory adjustments or short-term market overreactions. An MA() process is always stationary, but it must satisfy the invertibility condition (roots of outside the unit circle) to be expressed as an infinite AR process.
ARMA Models: Unifying AR and MA
When both autoregressive and moving-average dynamics are present, we obtain the ARMA() model:
ARMA models provide a parsimonious description of stationary time series. They are a cornerstone of the Box–Jenkins methodology, which proceeds in three iterative steps:
- Identification: examine ACF and PACF to propose plausible orders .
- Estimation: fit the model via maximum likelihood (or conditional least squares).
- Diagnostic checking: verify that residuals resemble white noise; if not, refine the model.
ARIMA: Accommodating Non-Stationarity via Integration
When the series itself is not stationary but its -th difference is, we use an Autoregressive Integrated Moving Average model, denoted ARIMA(). Introducing the difference operator , where is the backshift operator, the model can be written as
The term removes unit roots, rendering the differenced series stationary. Most economic and business time series require or, occasionally, .
Economic Intuition: The integration component models random walks, which are foundational in the Efficient Market Hypothesis. A series with implies that shocks have a permanent effect on the level of the series, characteristic of stock prices or aggregate price levels, whereas the differenced series (returns or inflation) remains stationary.
Implementation in Python:
from statsmodels.tsa.arima.model import ARIMA
from sklearn.metrics import mean_squared_error
# Fit MA(1) model: order = (p,d,q) = (0,0,1)
model = ARIMA(traindata, order=(0,0,1))
ma_fit = model.fit()
predictions = ma_fit.predict(start=len(traindata),
end=len(traindata)+len(testdata)-1,
dynamic=False)
error = mean_squared_error(testdata, predictions)
The dynamic=False argument ensures one-step-ahead forecasts that use actual lagged values where available.
Seasonal ARIMA (SARIMA) and SARIMAX
Many series exhibit repeating seasonal patterns. SARIMA extends ARIMA by incorporating seasonal differencing and seasonal AR and MA components. The general seasonal model is denoted SARIMA, where is the seasonal period (e.g., 12 for monthly data). The formulation with backshift operators is:
with seasonal AR polynomial and seasonal MA polynomial .
The SARIMAX model extends SARIMA by incorporating exogenous regressors:
This bridges the gap between pure time series analysis and regression, allowing analysts to control for known external interventions such as holiday effects, marketing campaigns, or macroeconomic indicators.
import statsmodels.api as sm
from statsmodels.tsa.stattools import adfuller
# 1. Stationarity Check
adf_result = adfuller(series.dropna())
print(f'ADF Statistic: {adf_result[0]:.4f}, p-value: {adf_result[1]:.4f}')
# 2. Train-Test Split
train_size = int(len(series) * 0.8)
train, test = series[:train_size], series[train_size:]
# 3. Fit SARIMA Model
model = sm.tsa.SARIMAX(train, order=(1, 1, 1), seasonal_order=(1, 1, 1, 12))
results = model.fit(disp=False)
print(results.summary())
# 4. Forecasting and Visualization
forecast = results.get_forecast(steps=len(test))
pred_mean = forecast.predicted_mean
conf_int = forecast.conf_int(alpha=0.05)
plt.figure(figsize=(12, 6))
plt.plot(train.index, train, label='Training Data', color='blue')
plt.plot(test.index, test, label='Actual Test Data', color='green')
plt.plot(pred_mean.index, pred_mean, label='SARIMA Forecast', color='red', linewidth=2)
plt.fill_between(conf_int.index, conf_int.iloc[:, 0], conf_int.iloc[:, 1],
color='pink', alpha=0.3, label='95% Confidence Interval')
plt.title('SARIMA Forecast with Prediction Intervals')
plt.xlabel('Time')
plt.ylabel('Value')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
Multivariate Time Series Forecasting
The Vector Autoregressive (VAR) Foundation
The VAR() model for a -dimensional vector is written as
where is a vector of intercepts, each is a coefficient matrix, and is a -dimensional white noise process. The covariance matrix is positive definite, allowing for instantaneous correlations across equations — a crucial feature that distinguishes VARs from separate univariate regressions. Using the lag operator, the compact polynomial form is , with .
The model is stable (stationary) if all roots of the determinantal equation lie outside the unit circle. Under stability, the process has a causal infinite-order VMA() representation.
Moving Average Components: The VARMA Model
The VARMA() model adds moving average terms:
or in lag operator notation, , where . The process is invertible if all roots of lie outside the unit circle. The identification of VARMA models is more delicate than in the univariate case because the matrices and can be multiplied by any non-singular rotation without changing the second-order properties. Standard practice imposes a canonical form, such as the echelon form.
Estimation of VARMA Models
Estimation typically proceeds via maximum likelihood under the assumption of Gaussian innovations. The conditional Gaussian log-likelihood is
where are computed recursively given the parameter matrices. For pure VAR models, equation-by-equation OLS is equivalent to multivariate least squares and provides consistent estimates, but for VARMA the likelihood is inherently non-linear.
Model Selection and Diagnostic Checking
Choosing the orders requires a balance between fit and parsimony. Information criteria are computed over a grid of plausible orders:
where is the total number of estimated parameters. After fitting, the residuals should resemble white noise. Diagnostics include multivariate portmanteau tests such as the Ljung–Box on residual cross-correlations:
where is the sample autocovariance matrix at lag .
Forecasting with VARMA Models
Once an adequate VARMA has been estimated, optimal -step-ahead forecasts are obtained by iterating the dynamic equations while setting future innovations to their expected value of zero:
A critical tool for interpretation is the forecast error variance decomposition (FEVD), which quantifies the proportion of the -step forecast variance of each variable attributable to its own innovations versus those of other variables.
Incorporating Exogenous Regressors: VARMAX
The VARMAX model extends VARMA by including current and lagged values of a -dimensional vector of exogenous variables :
Here each is a matrix of coefficients. The term is assumed fully predetermined or strictly exogenous. In financial forecasting, a VARMAX model might predict stock returns and trading volume (endogenous variables) using macroeconomic indicators like unemployment rates or monetary policy decisions (exogenous variables).
Visualization Strategies for Multivariate Forecasts
- Impulse Response Functions (IRFs): Plot the dynamic response of each variable to a one-standard-deviation shock in another variable. IRFs reveal the propagation mechanism and persistence of shocks through the system.
- Forecast Error Variance Decomposition (FEVD): Visualize the proportion of forecast error variance for each variable attributable to shocks from other variables.
- Multi-panel forecast plots: Display actual versus predicted values for all variables in a grid layout, with confidence bands indicating forecast uncertainty.
- Coefficient heatmaps: For large systems, visualize the AR and MA coefficient matrices as heatmaps to identify strong interdependencies.
from statsmodels.tsa.statespace.varmax import VARMAX
# Fit VARMA(1,1) model
model = VARMAX(endog=data, order=(1, 1), trend='c')
results = model.fit(disp=False)
# Forecast
forecast = results.forecast(steps=12)
# Impulse Response Analysis
irf = results.impulse_responses(steps=20, orthogonalized=True)
Exponential Smoothing Models
Exponential Smoothing constitutes a foundational family of time series forecasting methods that generate predictions by applying exponentially decreasing weights to past observations. Unlike simple moving averages, which assign equal weight to a fixed window of historical data, exponential smoothing models operate on the premise that recent observations contain more predictive information than distant ones.
Simple Exponential Smoothing (SES)
Simple Exponential Smoothing is the most basic formulation, designed strictly for time series data that exhibit no discernible trend or seasonality. The model relies on a single parameter, the smoothing factor , which governs the rate at which the influence of past observations decays.
Let denote the observed value at time . The smoothed statistic , which represents the level of the series, is updated recursively:
where . To understand the economic and statistical intuition behind this formulation, we can expand the recursive equation through backward substitution:
By induction, assuming the process extends infinitely into the past, the smoothed value is an infinite weighted sum of all past observations:
Thus, the weight assigned to observation is , which decays geometrically with lag . When is close to 1, the series adapts quickly to new observations; a smaller produces a smoother level that reacts sluggishly to transient shocks. The forecast for all future periods is constant and equals the most recent level:
The parameter is usually chosen by minimizing the sum of squared one-step-ahead forecast errors over the training set. SES can be cast as a special case of the ARIMA(0,1,1) model, which provides a statistical framework for inference.
Python Implementation:
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.api import SimpleExpSmoothing
# Sample data
data = [41.7275, 24.0418, 32.3281, 37.3287, 46.2132,
29.3463, 36.4829, 42.9777, 48.9015, 31.1802,
37.7179, 40.4202, 51.2069, 31.8872, 40.9783,
43.7725, 55.5586, 33.8509, 42.0764, 45.6423,
59.7668, 35.1919, 44.3197, 47.9137]
index = pd.date_range(start="2005", end="2010-Q4", freq="QS-OCT")
series = pd.Series(data, index)
train = series.iloc[:-5]
test = series.iloc[-5:]
model = SimpleExpSmoothing(train, initialization_method="heuristic")
ses_fit = model.fit(smoothing_level=0.2, optimized=False)
forecast = ses_fit.forecast(steps=5)
plt.figure(figsize=(10,6))
plt.plot(train, label='Training data', color='black')
plt.plot(test, label='Test data', color='blue', marker='o')
plt.plot(forecast, label='SES Forecast (α=0.2)', color='red', linestyle='--', marker='s')
plt.title('Simple Exponential Smoothing')
plt.legend()
plt.xlabel('Date')
plt.ylabel('Value')
plt.grid(alpha=0.3)
plt.show()
Holt's Linear Trend Method
When a time series exhibits a clear trend, SES is inadequate because its forecasts remain constant indefinitely. extended the method by adding a second equation to capture a (local) linear trend:
where controls the level adaptation, and controls the trend adaptation. The -step-ahead forecast is:
A damped trend variant, which prevents the forecast from growing indefinitely, multiplies the trend term by a damping factor , yielding . This is often more robust in practice, especially for long-range forecasts.
Holt-Winters Seasonal Method
The Holt-Winters method extends Holt's formulation by incorporating a seasonal component. The model exists in two variants depending on the nature of the seasonality:
Additive Holt-Winters (seasonal fluctuations are roughly constant over time):
The forecast for periods ahead is , where ensures the most recent relevant seasonal factor is used.
Multiplicative Holt-Winters (seasonal variation scales with level):
The multiplicative forecast is .
The ETS Framework and Prediction Intervals
Modern implementations of exponential smoothing are grounded in the ETS (Error, Trend, Seasonal) state-space framework. This statistical formulation not only unifies the various exponential smoothing methods but also provides a rigorous basis for calculating prediction intervals. By modeling the error term explicitly (either additive or multiplicative), the ETS framework allows analysts to quantify forecast uncertainty, which widens as the forecast horizon increases.
from statsmodels.tsa.holtwinters import ExponentialSmoothing
# Fit Multiplicative Holt-Winters model with damped trend
hw_model = ExponentialSmoothing(
train_hw,
trend='add',
seasonal='mul',
seasonal_periods=12,
damped_trend=True,
initialization_method="estimated"
)
hw_fit = hw_model.fit(optimized=True)
# Forecast and extract prediction intervals
hw_forecast = hw_fit.forecast(steps=12)
pred_obj = hw_fit.get_prediction(start=train_hw.index[0], end=test_hw.index[-1])
pred_summary = pred_obj.summary_frame(alpha=0.05)
fig, ax = plt.subplots(figsize=(14, 7))
ax.plot(train_hw.index, train_hw, label='Training Data', color='black', lw=1.5)
ax.plot(test_hw.index, test_hw, label='Actual Test Data', color='blue', marker='o')
ax.plot(test_hw.index, hw_forecast, label='Holt-Winters Forecast', color='red', lw=2)
ax.fill_between(test_hw.index,
pred_summary['pi_lower'].iloc[-12:],
pred_summary['pi_upper'].iloc[-12:],
color='pink', alpha=0.3, label='95% Prediction Interval')
ax.set_title("Holt-Winters Exponential Smoothing with Prediction Intervals")
ax.legend()
plt.tight_layout()
plt.show()