Your First Detection
This tutorial mirrors the examples/01_quickstart.ipynb notebook
and shows the minimum set of steps required to
detect changepoints with Fast-BOCPD.
1. Create a toy dataset
import numpy as np
np.random.seed(7)
regime_lengths = [120, 150, 90]
regime_means = [0.0, 1.5, -0.2]
data = np.concatenate([
np.random.normal(loc=mu, scale=0.2, size=n)
for n, mu in zip(regime_lengths, regime_means)
])
2. Instantiate a model and hazard
Fast-BOCPD provides conjugate observation models out of the box. For continuous,
roughly Gaussian data we use fast_bocpd.models.GaussianNIG. The hazard
controls expected segment length.
from fast_bocpd import BOCPD, GaussianNIG, ConstantHazard
obs_model = GaussianNIG(mu0=0.0, kappa0=1.0, alpha0=0.2, beta0=0.2)
hazard = ConstantHazard(lambda_=150) # Expect ≈150 samples per regime
bocpd = BOCPD(obs_model=obs_model, hazard=hazard, max_run_length=600)
3. Stream observations
BOCPD.update(x) returns the posterior run-length distribution and the
probability that the current point is a changepoint.
cp_probs = []
map_run_lengths = []
for x in data:
posterior_r, cp_prob = bocpd.update(float(x))
cp_probs.append(cp_prob)
map_run_lengths.append(bocpd.get_map_run_length())
4. Simple alerting
Raise an alert whenever cp_prob crosses a threshold from below or the MAP
run length resets to zero.
alerts = []
THRESHOLD = 0.3
for i, (cp_prob, map_r) in enumerate(zip(cp_probs, map_run_lengths)):
if cp_prob >= THRESHOLD and map_r <= 2:
alerts.append(i)
print(f\"Detected {len(alerts)} changepoints: {alerts}\")
5. Visualize
Plot the time series, P(r_t=0) and MAP run length to sanity check the
detector. See examples/_helpers.py for Plotly helpers or use Matplotlib:
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=(12, 6))
ax1.plot(data, color=\"#4E79A7\", linewidth=1.5)
for idx in alerts:
ax1.axvline(idx, color=\"red\", linestyle=\"--\", alpha=0.6)
ax1.set_ylabel(\"Observation\")
ax2.plot(cp_probs, color=\"#F28E2B\", linewidth=1.5, label=\"P(CP)\")
ax2_twin = ax2.twinx()
ax2_twin.plot(map_run_lengths, color=\"#59A14F\", linewidth=1.2, label=\"MAP run length\")
ax2.set_xlabel(\"Time step\")
ax2.set_ylabel(\"P(CP)\")
ax2_twin.set_ylabel(\"MAP run length\")
plt.tight_layout()
Next steps
Swap
GaussianNIGwith the model that matches your data type (see Stock Volatility Detection for Gamma data).Use
fast_bocpd.utils.OnlineChangeDetectorto handle thresholds, cooldowns, and metadata automatically once you move beyond a prototype.