Skip to contents

Wraps the ocd package (Chen, Wang and Samworth, 2022): online multiscale detection of a mean change in a high-dimensional stream, with worst-case detection-delay guarantees and per-observation cost independent of history. The detector assumes standardised data with known pre-change mean; this wrapper estimates the baseline mean and standard deviation from an initial training window, then monitors the remainder of the series, resetting after each declaration so multiple changes can be found.

Usage

ocd_wrapper(
  x,
  train = NULL,
  thresh = "MC",
  patience = 5000,
  beta = 1,
  mc_reps = 100,
  ...
)

Arguments

x

A numeric matrix or data frame with one row per time point and at least two columns. The ocd detector is inherently high-dimensional and cannot be constructed for a single coordinate, so univariate input is rejected; use a univariate engine (see cpt_methods()) for one series.

train

Number of initial observations used to estimate the baseline mean/sd (not monitored). Defaults to max(20, floor(0.2 * n)), capped at n/2.

thresh

Threshold specification passed to ocd::ChangepointDetector(); "MC" (default) calibrates by Monte Carlo, which is what makes this the slowest wrapper (see the timing note below). Supplying the three thresholds directly, as a named numeric vector c(diag =, off_d =, off_s =), skips calibration altogether.

patience

Target average run length to false alarm. Defaults to 5000.

beta

Assumed lower bound on the squared Euclidean norm of the mean change. Defaults to 1.

mc_reps

Monte Carlo repetitions for threshold calibration. Defaults to 100. The cost is linear in this and grows with the number of coordinates; see the timing note below.

...

Additional arguments passed to ocd::ChangepointDetector().

Value

A ggcpt object. Because the detector is online, reported locations are declaration times (the changepoint plus the detection delay). The declared_at column holds the same values as cp, and deliberately: ocd declares a change without also estimating where it began, so there is no separate location for the second column to carry. Compare cpm_wrapper(), whose engine supplies both, and whose cp is an estimated location with detection_time strictly later.

How long this takes

Nearly all of the run time is ocd's Monte Carlo threshold calibration, which happens before a single observation is read. It is linear in mc_reps and grows with the number of coordinates. Timed on one Linux x86-64 machine at mc_reps = 5, construction took about 10 s at \(p = 3\), 22 s at \(p = 10\) and 113 s at \(p = 50\); raising mc_reps scales it linearly, so at \(p = 3\) it was 38 s at mc_reps = 20 and 189 s at the default mc_reps = 100. The practical reading is that the default costs minutes rather than seconds even for a handful of coordinates, and better than half an hour at \(p = 50\). Another machine will give different absolute numbers; the linearity in mc_reps is the part to plan around. Monitoring the observations afterwards is cheap by comparison: 0.37 s for a thousand of them at \(p = 3\). Lower mc_reps while exploring (the example below uses 2, which measures 3.8 s), or pass thresh directly to skip calibration entirely, which brings the same fit down to a tenth of a second.

References

Chen Y, Wang T, Samworth RJ (2022). “High-dimensional, multiscale online changepoint detection.” Journal of the Royal Statistical Society: Series B, 84(1), 234–266.

Examples

# \donttest{
set.seed(2026)
X <- rbind(matrix(rnorm(60 * 3), 60), matrix(rnorm(40 * 3, 3), 40))
# `mc_reps = 2`, not the default 100 and not the 5 this example used to
# pass: the calibration is linear in `mc_reps` and is nearly all of the
# cost, so 5 measured 9.7 s here against CRAN's 5 s budget and 2
# measures 3.8 s for the same answer. Neither is a calibration you
# would trust -- see the timing section above.
res <- ocd_wrapper(X, mc_reps = 2)
res$changepoints
#> # A tibble: 1 × 3
#>      cp cp_value declared_at
#>   <int>    <dbl>       <int>
#> 1    62     4.31          62
# }