Topics
Gaussian Processes (GPs) are a highly flexible Bayesian tool that can be employed in a variety of modeling tasks, including time-series analysis. While traditional methods like ARIMA focus on generative processes, Gaussian Processes approach the problem from a curve-fitting perspective, allowing the user to define how different temporal components—such as trend, seasonality, and noise—should behave. This post examines the mechanics of GPs, how they work in the context of time-series data, and practical ways to implement them using Python.
The main advantage of a GP is not only the forecast mean. It is the explicit uncertainty around the forecast and the ability to encode structure through kernels. That makes GPs useful when observations are sparse, measurement noise matters, or a domain expert can describe the shape of the process better than a black-box model can infer it from data alone.
Simulating Time Series Data
We start by simulating some time-series data that reflects common real-world temporal dynamics—periodicity (seasonality) and a trend.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np
import matplotlib.pyplot as plt
# Simulate time series data
np.random.seed(123)
x = np.linspace(0, 4 * np.pi, 100)
y = 3 * np.sin(2 * x) + np.random.rand(100) * 2
trend = 0.08 * np.arange(1, 101)
y += trend
# Plot the time series data
plt.plot(np.arange(1, 101), y, label='Data')
plt.xlabel('Timepoint')
plt.ylabel('Values')
plt.title('Simulated Time Series Data')
plt.show()
This code generates a noisy sine wave with an upward trend, simulating periodic and linear components often seen in time-series data.
Time Series Decomposition
Time-series analysis often revolves around decomposing a dataset into key components, such as:
- Trend: Does the data exhibit a consistent increase or decrease over time?
- Autocorrelation: How correlated are data points with past values?
- Seasonality: Are there recurring patterns, such as daily or yearly cycles?
We can decompose a time series into these components and model each one separately. This decomposition process lays the foundation for modeling with Gaussian Processes, as we later combine different GP kernels to capture these dynamics.
Gaussian Processes Explained
A Gaussian process is a stochastic process for which every finite collection of function values has a multivariate normal distribution. It defines a prior over functions through a mean function and covariance kernel, with the kernel determining which functions receive substantial prior probability. The model is therefore characterized by two coupled ingredients rather than by a generic claim that it represents “all possible functions”:
- Mean function ($m(x)$): often set to zero after centering or when the kernel is expected to carry the structure, but nonzero parametric mean functions can be important for extrapolation.
- Covariance function ($k(x, x')$): Determines how different points in the input space are related. The choice of kernel is crucial for controlling the smoothness, periodicity, and other aspects of the function.
Mathematically, the GP is written as:
The covariance function $k(x,x')$, usually called the kernel, determines how function values co-vary across inputs and therefore encodes assumptions about smoothness, periodicity, characteristic length scales, and other structural properties. Kernel choice is consequently a modeling assumption rather than a purely technical tuning decision.
Covariance Functions (Kernels)
Exponentiated Quadratic Kernel
The most common GP kernel, also called the Radial Basis Function (RBF) or squared exponential kernel, controls the "wiggliness" of the function. Its formula is:
Where $\sigma$ is the variance, and $l$ is the lengthscale, controlling how quickly the function varies.
1
2
3
4
def cov_exp_quad(xa, xb, sigma, l):
"""Exponentiated Quadratic Kernel"""
sq_dist = np.subtract.outer(xa, xb) ** 2
return sigma ** 2 * np.exp(-0.5 * sq_dist / l ** 2)
Periodic Kernel
A periodic kernel models cyclic behavior, making it useful for capturing seasonality in time-series data:
Here, $p$ controls the period of repetition.
1
2
3
4
def cov_periodic(xa, xb, sigma, l, p):
"""Periodic Kernel"""
sin_dist = np.sin(np.pi * np.abs(np.subtract.outer(xa, xb)) / p)
return sigma ** 2 * np.exp(-2 * (sin_dist ** 2) / l ** 2)
Combining Kernels
Kernel composition is useful because sums and products of valid kernels remain valid kernels and correspond to interpretable combinations of covariance structure. A sum of a smooth component and a periodic component can represent a latent function containing both slowly varying and seasonal behavior, while observation noise belongs in the likelihood rather than being casually conflated with the latent covariance.
1
2
3
4
5
6
# Combining kernels over the input index, not the observed target values
x_train = np.arange(1, 101)
Sigma_exp_quad = cov_exp_quad(x_train, x_train, 1, 20)
Sigma_periodic = cov_periodic(x_train, x_train, 1, 3, 25)
Sigma_white_noise = np.eye(len(Sigma_exp_quad)) * 0.01
Sigma_comb = Sigma_exp_quad + Sigma_periodic + Sigma_white_noise
Fitting Gaussian Processes
After defining our covariance structure, we can now fit the GP to our data, first by sampling from the prior to visualize what plausible functions might look like.
Sampling from the Prior
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import scipy.stats as stats
def sample_gp_prior(Sigma, n_samples=5):
"""Sample from the GP prior using the covariance matrix"""
return np.random.multivariate_normal(mean=np.zeros(Sigma.shape[0]), cov=Sigma, size=n_samples).T
# Sample from the GP prior
samples_prior = sample_gp_prior(Sigma_comb)
# Plot prior samples
plt.plot(np.arange(1, 101), samples_prior)
plt.title('Samples from GP Prior')
plt.xlabel('Timepoint')
plt.ylabel('Values')
plt.show()
The prior reveals candidate functions that our GP believes are plausible fits before seeing any data.
Predicting from the Posterior
Once we incorporate the observed data, the GP updates its beliefs, and we can make predictions using the posterior distribution.
```python def gp_posterior(x_train, x_pred, y_train, kernel, noise=0.05, **kernel_params): """Calculate the GP posterior mean and covariance matrix""" K = kernel(x_train, x_train, **kernel_params) + noise ** 2 * np.eye(len(x_train)) K_s = kernel(x_train, x_pred, **kernel_params) K_ss = kernel( x_pred, x_pred, **kernel_params, ) # Avoid forming K^{-1} explicitly. alpha = np.linalg.solve( K, y_train, )
v = np.linalg.solve( K, K_s, )
1
2
3
4
5
# Posterior mean
mu_s = K_s.T @ alpha
# Posterior covariance
cov_s = K_ss - K_s.T @ v
return mu_s, cov_s
Define training data and new points to predict
x_pred = np.linspace(1, 100, 50) y_train = y
Compute posterior mean and covariance
mu_s, cov_s = gp_posterior(x_train, x_pred, y_train, kernel=cov_exp_quad, sigma=1, l=75)
Plot posterior mean
plt.plot(x_pred, mu_s, label='Posterior Mean') std_latent = np.sqrt( np.clip( np.diag(cov_s), 0.0, None, ) )
plt.fill_between( x_pred, mu_s - 1.96 * std_latent, mu_s + 1.96 * std_latent, alpha=0.1, label="95% latent-function credible band", ) plt.scatter(x_train, y_train, label='Training Data') plt.title('GP Posterior') plt.xlabel('Timepoint') plt.ylabel('Value') plt.legend() plt.show() ``` Gaussian Processes offer a flexible and interpretable approach to modeling time series. By carefully selecting and combining kernels, we can capture trends, seasonality, and noise, making them an invaluable tool in the machine learning and statistical toolkit.
Practical Limitations
Gaussian Processes are elegant, but they are not a free replacement for every forecasting model:
- Computational cost: exact GP inference scales cubically with the number of observations, so large datasets need sparse or approximate GP methods.
- Kernel misspecification: a poorly chosen kernel can make the posterior look precise while missing the real structure of the process.
- Extrapolation: GPs extrapolate according to the kernel assumptions. If the future regime changes, the uncertainty bands may still be misleading.
- Feature design: for multivariate time series, calendar effects, interventions, and external regressors must be encoded deliberately.
Use GPs when uncertainty, smoothness assumptions, and interpretable structure are important. For high-volume operational forecasting, compare them against simpler state-space, ARIMA, gradient boosting, and deep learning baselines.
Latent-function uncertainty versus observation uncertainty
The posterior covariance above is for the latent function $f(x)$. If a future observation satisfies
\[y_\ast = f(x_\ast) + \varepsilon_\ast, \qquad \varepsilon_\ast \sim N(0,\sigma_n^2),\]then predictive variance for the observation adds the noise variance:
\[\operatorname{Var}(y_\ast\mid D) = \operatorname{Var}(f_\ast\mid D) + \sigma_n^2.\]Do not mix the two. A credible band for the latent smooth function is narrower than a predictive interval for a noisy future measurement.
Hyperparameters are estimated too
The examples treat kernel amplitude, length scale, period, and noise level as fixed. In real applications those quantities are often estimated by maximizing the marginal likelihood or assigned priors. Plug-in hyperparameters understate uncertainty when hyperparameter posterior uncertainty is substantial.
Mean functions and extrapolation
A zero-mean GP with a stationary kernel tends back toward its prior mean far from the observed data. If the scientific process has a persistent linear trend or mechanistic baseline, encode it in the mean function or kernel rather than expecting an RBF kernel to extrapolate the trend indefinitely.
Numerical stability
Exact GP calculations are commonly implemented with Cholesky factorization rather than generic matrix inversion. Add a small jitter term only when justified for numerical conditioning, and distinguish that numerical jitter from the observation-noise parameter.
References
- Rasmussen, C. E., & Williams, C. K. I. (2006). Gaussian Processes for Machine Learning. MIT Press.
- Box, G. E. P., Jenkins, G. M., Reinsel, G. C., & Ljung, G. M. (2015). Time Series Analysis: Forecasting and Control (5th ed.). Wiley.
- Gelman, A., Carlin, J. B., Stern, H. S., Dunson, D. B., Vehtari, A., & Rubin, D. B. (2013). Bayesian Data Analysis (3rd ed.). CRC Press.
- Roberts, S., Osborne, M., Ebden, M., Reece, S., Gibson, N., & Aigrain, S. (2013). Gaussian processes for time-series modelling. Philosophical Transactions of the Royal Society A, 371(1984).
Embed interactive plots, widgets, and demos using <figure>, <iframe>, or <div class="interactive-embed"> containers. Ensure each embed includes descriptive captions for accessibility.
How to cite
Use the quick export buttons to save citations for reference managers or copy the formatted text directly.
Diogo Ribeiro (2023). Gaussian Processes for Time-Series Analysis in Python. Faculty of Media Arts and Design, Technical University of Porto. https://diogoribeiro7.github.io/machine-learning/guassian_processes/.


