Creates a detector that consumes observations as they arrive and raises
alarms, rather than segmenting a series that is already complete. Feed it
with cpt_update(), read its alarm log with
alarms(), and score it with cpt_delay() —
because for an online method "did you find the location?" is the wrong
question and "how long did you take, and how often do you false-alarm?"
is the right one.
Usage
cpt_monitor(
method = c("edetector", "cpm", "ocd"),
baseline = NULL,
alpha = 0.01,
arl0 = 500,
cpm_type = "Mann-Whitney",
patience = 5000,
deltas = c(0.5, 1, 2),
reset = TRUE,
relearn = 20,
thresh = "MC",
mc_reps = 100,
...
)
# S3 method for class 'ggcpt_monitor'
tidy(x, ...)
# S3 method for class 'ggcpt_monitor'
print(x, ...)
# S3 method for class 'ggcpt_monitor'
autoplot(object, plot_type = c("timeline", "statistic", "runlength"), ...)Arguments
- method
Which sequential detector:
"edetector"(default) a mixture Shiryaev–Roberts e-detector; see the section below.
"cpm"cpm's sequential change-point model, tuned by
ARL0."ocd"ocd's high-dimensional online detector. Multivariate only – it tracks a projection of the whole vector and needs at least two coordinates, so it refuses a single series rather than falling back to a univariate statistic.
- baseline
A numeric vector (or, for
"ocd", a matrix with rows as time points) of pre-change training data used to estimate the in-control mean and scale. Required for"edetector"and"ocd"; optional for"cpm", which has its own start-up period.- alpha
Target false-alarm probability for
"edetector": the average run length under the null is at least1 / alpha, by optional stopping on the martingale \(M_t - t\) (see Details). Defaults to0.01.- arl0
Target in-control average run length for
"cpm". Defaults to500.- cpm_type
Statistic for
"cpm". Defaults to"Mann-Whitney".- patience
Target patience (average run length) for
"ocd". Defaults to5000.- deltas
Shift sizes, in baseline standard deviations, mixed over by
"edetector". Defaults toc(0.5, 1, 2), each taken in both directions. The mixture is a uniform average, so adding shifts costs power at the ones already there rather than inflating the false-alarm rate; mix over the range you think the change could fall in, not over everything.- reset
After an alarm, restart the detector (
TRUE, the default) or leave it running? Restarting is what makes a monitor report repeated changes rather than latching on the first one.- relearn
How many observations after an alarm are used to re-learn the in-control baseline, during which no further alarm can fire. Defaults to
20. This matters more than it looks: a real change is persistent, so a detector that restarts against the stale pre-change baseline alarms again on the very next observation and keeps alarming for the rest of the series — the monitor reports one change as hundreds, andcpt_delay()then counts them all as false alarms. Setrelearn = 0to switch the behaviour off and see every threshold crossing.- thresh
Threshold rule for
"ocd":"MC"(default) calibrates by Monte Carlo againstpatience, or supply a numeric vector of three thresholds. The Monte Carlo calibration is the expensive part of building an"ocd"monitor — a minute or more at the defaultpatience— so pass thresholds directly when you already have them, or lowermc_repswhile exploring.- mc_reps
Monte Carlo repetitions for the
"ocd"threshold.- ...
Additional arguments passed to the engine's constructor.
- x
A
ggcpt_monitorobject (forprint()).- object
A
ggcpt_monitorobject (forautoplot()).- plot_type
"timeline"(the monitored series with the alarms marked),"statistic"(the running detection statistic against its threshold) or"runlength"(the gaps between alarms, which estimate the run length). For a multivariate monitor the timeline draws the first coordinate — the alarms are shared, so the rules are right whichever coordinate is shown, but the line is one of several.
The e-detector, and why it is implemented rather than wrapped
Shin, Ramdas and Rinaldo (2023) give a nonparametric sequential framework with non-asymptotic control of the average run length, and it has no R implementation. The construction used here is the mixture Shiryaev–Roberts e-detector for a sub-Gaussian shift. For each candidate shift \(\delta\) the increment is the likelihood ratio \(e_t^{(\delta)} = \exp(\delta (X_t - \mu_0)/\sigma^2 - \delta^2/(2\sigma^2))\), which has unit mean under the null; the running statistic is \(R_t^{(\delta)} = (1 + R_{t-1}^{(\delta)}) e_t^{(\delta)}\); the shifts are combined by averaging, \(M_t = K^{-1} \sum_\delta R_t^{(\delta)}\); and an alarm is raised the first time \(M_t \ge 1/\alpha\).
The averaging is not a detail. Under the null \(M_t - t\) is a mean-zero martingale, so optional stopping at the alarm time \(\tau\) gives \(E_\infty[\tau] = E_\infty[M_\tau] \ge 1/\alpha\): a finite-sample lower bound on the in-control average run length, with no asymptotics and no calibration run. A convex combination of e-detectors is an e-detector; a maximum of them is not, and taking one silently multiplies the false-alarm rate by roughly the number of shifts mixed over. Every other detector in this package wraps published, separately maintained code; this one does not, and is labelled as such wherever it appears.
References
Shin J, Ramdas A, Rinaldo A (2023). “E-detectors: a nonparametric framework for sequential change detection.” The New England Journal of Statistics in Data Science, 1(2), 229–260. doi:10.51387/23-NEJSDS49 .
Examples
set.seed(2026)
mon <- cpt_monitor("edetector", baseline = rnorm(100))
mon <- cpt_update(mon, rnorm(50)) # still in control
mon <- cpt_update(mon, rnorm(50, 3)) # a change arrives
alarms(mon)
#> # A tibble: 1 × 3
#> time statistic threshold
#> <int> <dbl> <dbl>
#> 1 51 134. 100
