Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Self-exciting Hawkes Process — From Scratch and With NumPyro

Open In Colab

A Hawkes process has a self-exciting conditional intensity: past events temporarily raise the rate of future events. With an exponential kernel,

λ∗(t)=μ+α∑ti<te−β(t−ti).\lambda^*(t) = \mu + \alpha \sum_{t_i < t} e^{-\beta (t - t_i)}.

The process is sub-critical (stationary) when α/β<1\alpha / \beta < 1. The compensator on [0,T][0, T] has the closed form

Λ(T)=μT+αβ∑i(1−e−β(T−ti)).\Lambda(T) = \mu T + \frac{\alpha}{\beta} \sum_i \big(1 - e^{-\beta (T - t_i)}\big).

This notebook walks through the two APIs:

  1. From scratch — use the primitives exp_hawkes_sample, exp_hawkes_intensity, exp_hawkes_log_prob to simulate and sanity-check.

  2. With NumPyro — wrap the process in the ExponentialHawkes distribution and run NUTS to recover (μ,α,β)(\mu, \alpha, \beta) from synthetic data.

Setup

/home/azureuser/localfiles/xtremax/.venv/bin/python: No module named pip
Note: you may need to restart the kernel to use updated packages.
/home/azureuser/localfiles/xtremax/.venv/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm

1. From Scratch: Primitives

Simulate an aftershock-style cluster with μ=0.5\mu = 0.5, α=0.6\alpha = 0.6, β=1.2\beta = 1.2 (α/β=0.5\alpha/\beta = 0.5, comfortably sub-critical).

n events = 32, expected ~ 30.0

Plot the intensity path alongside the events — the characteristic Hawkes “jumps-then-decay” is clearly visible.

<Figure size 1000x400 with 1 Axes>

Diagnostic: time-rescaling residuals

Under the time-rescaling theorem τi=Λ(ti)−Λ(ti−1)\tau_i = \Lambda(t_i) - \Lambda(t_{i-1}) is iid Exp(1)\mathrm{Exp}(1) when the compensator is correct. Using the wrong compensator (e.g. assuming HPP) breaks the fit obviously.

KS statistic vs Exp(1) = 0.095
KS statistic under wrong (HPP) compensator = 0.101
<Figure size 600x400 with 1 Axes>

2. With NumPyro: Parameter Inference

Generate a longer sequence and recover (μ,α,β)(\mu, \alpha, \beta) via NUTS.

observed 211 events on [0, 200.0]
mu    posterior = 0.739 ± 0.112  (truth 0.6)
alpha posterior = 0.313 ± 0.103  (truth 0.4)
beta  posterior = 1.068 ± 0.399  (truth 1.0)
<Figure size 1200x350 with 3 Axes>

All three parameters are recovered; the branching ratio α/β\alpha / \beta is the hardest to pin down because the compensator factors alpha and beta through the same Λ(T)\Lambda(T) term — more events and longer TT tighten it.