| Title: | Anytime-Valid Control Charts with E-Detectors |
|---|---|
| Description: | Sequential change detection for process monitoring with e-detectors (Shin, Ramdas and Rinaldo, 2024, <doi:10.51387/23-NEJSDS51>): nonparametric, anytime-valid analogues of the CUSUM and Shiryaev-Roberts charts whose average run length to a false alarm is guaranteed for every distribution in a declared pre-change class (bounded, sub-Gaussian, Bernoulli or Poisson observations). Phase I/Phase II workflow, individual, p, c, u and regression charts, run-length simulation and auditable alarm reports. |
| Authors: | André Leite [aut, cre] (ORCID: <https://orcid.org/0000-0002-4718-9766>), Raydonal Ospina [aut] (ORCID: <https://orcid.org/0000-0002-9884-9090>), Cristiano Ferraz [aut] (ORCID: <https://orcid.org/0000-0002-6838-6734>) |
| Maintainer: | André Leite <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 0.1.0 |
| Built: | 2026-10-21 17:43:00 UTC |
| Source: | https://github.com/cran/edetect |
Two panels: the observations (as values, proportions or rates per unit exposure) with the pre-change centre, and the evidence of the detector on the log10 scale with the alarm threshold and, if any, the alarm time and the estimated change point.
## S3 method for class 'edetect_chart' autoplot(object, ...)## S3 method for class 'edetect_chart' autoplot(object, ...)
object |
An |
... |
Unused. |
A ggplot.
chart <- edetect_c(x = c(3, 2, 4, 3, 8, 9, 11, 10), center = 3, arl = 100) autoplot(chart)chart <- edetect_c(x = c(3, 2, 4, 3, 8, 9, 11, 10), center = 3, arl = 100) autoplot(chart)
The alarm status of a detector
edetect_alarm(state)edetect_alarm(state)
state |
An |
A one-row tibble with alarm (logical), alarm_time, evidence
at the alarm (or the current evidence), threshold, change_estimate
(the start of the e-process that carries most of the current evidence)
and n_observed.
design <- edetect_design(arl = 100, class = "subgaussian", center = 0, sigma = 1) state <- edetect_update(edetect_init(design), rnorm(10)) edetect_alarm(state)design <- edetect_design(arl = 100, class = "subgaussian", center = 0, sigma = 1) state <- edetect_update(edetect_init(design), rnorm(10)) edetect_alarm(state)
Estimates the average run length to a false alarm (ARL, no change) or the detection delay (with a change) of an e-detector design by Monte Carlo. The recursion is vectorised across replications.
edetect_arl( design, pre, post = NULL, change_at = 1L, n_rep = 200L, max_t = NULL )edetect_arl( design, pre, post = NULL, change_at = 1L, n_rep = 200L, max_t = NULL )
design |
An |
pre |
A function |
post |
Optional function with the same signature for post-change
observations. When supplied, the change happens at time |
change_at |
Time of the first post-change observation. |
n_rep |
Number of replications. |
max_t |
Censoring time; runs that have not alarmed by |
A list of class edetect_runs with runs (a tibble with one row
per replication: run_length, alarm, delay when there is a change,
false_alarm) and summary (a one-row tibble with the mean run length or
delay, its standard error, the censoring fraction and, with a change, the
false-alarm fraction before change_at).
design <- edetect_design(arl = 50, class = "subgaussian", center = 0, sigma = 1) set.seed(1) edetect_arl(design, pre = function(n) rnorm(n), n_rep = 50, max_t = 2000)$summary edetect_arl(design, pre = function(n) rnorm(n), post = function(n) rnorm(n, 1), change_at = 20, n_rep = 50, max_t = 500)$summarydesign <- edetect_design(arl = 50, class = "subgaussian", center = 0, sigma = 1) set.seed(1) edetect_arl(design, pre = function(n) rnorm(n), n_rep = 50, max_t = 2000)$summary edetect_arl(design, pre = function(n) rnorm(n), post = function(n) rnorm(n, 1), change_at = 20, n_rep = 50, max_t = 500)$summary
c chart: counts of nonconformities per unit
edetect_c(x, center = NULL, phase1 = NULL, ...)edetect_c(x, center = NULL, phase1 = NULL, ...)
x |
Counts per inspection unit. |
center |
Pre-change mean count; omit to estimate it from |
phase1 |
Optional Phase I counts (a numeric vector, unit exposure). |
... |
Passed to |
An edetect_chart.
chart <- edetect_c(x = c(3, 2, 4, 3, 8, 9, 11), center = 3, arl = 100) edetect_alarm(chart)chart <- edetect_c(x = c(3, 2, 4, 3, 8, 9, 11), center = 3, arl = 100) edetect_alarm(chart)
The classes of pre-change distributions for which edetect builds e-values.
Each class is a statement about the observations before a change; the
average run length guarantee holds for every distribution in the class.
edetect_classes()edetect_classes()
"bounded": observations in known bounds [a, b] with mean at most (direction
"up"), at least ("down") or equal to ("both") center. Nothing else is
assumed. E-values: "betting" (tight, default) or "hoeffding" (sub-Bernoulli).
"subgaussian": observations with mean center and sub-Gaussian tails with
declared scale sigma. Gaussian data with standard deviation sigma is the
boundary case; heavier tails violate the class.
"bernoulli": counts of successes in subgroups of size n, each trial with
conditional success probability (given the earlier trials of the subgroup) at
most/at least/equal to center; beyond that, dependence within a subgroup is
allowed. This is the p chart.
"poisson": counts with exposure n whose moment generating function is at
most that of a Poisson with rate center per unit exposure (Poisson and
underdispersed counts; overdispersed counts violate the class). These are the
c (n = 1) and u charts.
A character vector of class names.
edetect_classes()edetect_classes()
Fixes, before any Phase II observation is seen, everything the detector needs: the pre-change class and its parameters, the direction of the change to detect, the detector type (Shiryaev–Roberts or CUSUM), the family of e-values and the mixture over post-change alternatives, and the target average run length (ARL) to a false alarm.
edetect_design( arl = 370, class = edetect_classes(), center = NULL, bounds = NULL, sigma = NULL, direction = c("up", "down", "both"), type = c("sr", "cusum"), evalue = c("betting", "hoeffding"), delta = NULL, weights = NULL, phase1 = NULL )edetect_design( arl = 370, class = edetect_classes(), center = NULL, bounds = NULL, sigma = NULL, direction = c("up", "down", "both"), type = c("sr", "cusum"), evalue = c("betting", "hoeffding"), delta = NULL, weights = NULL, phase1 = NULL )
arl |
Target average run length to a false alarm. The alarm threshold
is |
class |
Pre-change class, see |
center |
Pre-change mean ( |
bounds |
Known bounds |
sigma |
Declared sub-Gaussian scale ( |
direction |
Change to detect: an increase ( |
type |
|
evalue |
E-value family for the |
delta |
Post-change shifts the mixture covers, in the units of the
observations (positive numbers; the sign follows |
weights |
Mixture weights over |
phase1 |
Optional Phase I (in-control) data: a numeric vector for the
|
The guarantee is distribution-free within the class: for every pre-change
distribution in it, the expected time to a false alarm is at least arl
(Shin, Ramdas and Rinaldo, 2024, Theorem 2.4), and the probability of a false
alarm by any time t, including data-dependent monitoring horizons, is at
most t / arl (Ramdas, 2026). The price is paid in detection delay, which
depends on the alternatives the mixture covers.
An object of class edetect_design.
Shin, J., Ramdas, A. and Rinaldo, A. (2024). E-detectors: a nonparametric framework for sequential change detection. The New England Journal of Statistics in Data Science, 2(2), 229–260. doi:10.51387/23-NEJSDS51
Ramdas, A. (2026). Universality of e-detectors for ARL control. arXiv:2608.12660.
edetect_design(arl = 370, class = "bounded", center = 0.5, bounds = c(0, 1)) edetect_design(arl = 500, class = "bernoulli", center = 0.02, direction = "up") edetect_design(arl = 370, class = "subgaussian", phase1 = rnorm(100), direction = "both")edetect_design(arl = 370, class = "bounded", center = 0.5, bounds = c(0, 1)) edetect_design(arl = 500, class = "bernoulli", center = 0.02, direction = "up") edetect_design(arl = 370, class = "subgaussian", phase1 = rnorm(100), direction = "both")
Initialise an e-detector
edetect_init(design)edetect_init(design)
design |
An |
An object of class edetect_chart holding the design, the running
state and an empty trajectory.
design <- edetect_design(arl = 370, class = "bounded", center = 0.5, bounds = c(0, 1)) state <- edetect_init(design) statedesign <- edetect_design(arl = 370, class = "bounded", center = 0.5, bounds = c(0, 1)) state <- edetect_init(design) state
p chart: proportion of nonconforming units
edetect_p(x, n, center = NULL, phase1 = NULL, ...)edetect_p(x, n, center = NULL, phase1 = NULL, ...)
x |
Counts of nonconforming units per subgroup. |
n |
Subgroup sizes (one per subgroup or a single value). |
center |
Pre-change proportion; omit to estimate it from |
phase1 |
Optional Phase I data frame with columns |
... |
Passed to |
An edetect_chart.
chart <- edetect_p(x = c(1, 0, 2, 1, 3, 4, 5, 6), n = 100, center = 0.01, arl = 100) edetect_alarm(chart)chart <- edetect_p(x = c(1, 0, 2, 1, 3, 4, 5, 6), n = 100, center = 0.01, arl = 100) edetect_alarm(chart)
Fits a linear model on Phase I data and monitors the Phase II residuals
y - prediction as a sub-Gaussian stream centred at zero, with the residual
standard deviation of the Phase I fit as the declared scale (or a sigma
supplied by the user). The fitted model is kept in the chart.
edetect_regression(formula, phase1, phase2, sigma = NULL, ...)edetect_regression(formula, phase1, phase2, sigma = NULL, ...)
formula |
Model formula. |
phase1 |
Phase I data frame. |
phase2 |
Phase II data frame with the same columns. |
sigma |
Declared sub-Gaussian scale of the residuals; default the Phase I residual standard deviation. |
... |
Passed to |
An edetect_chart with an extra element fit.
set.seed(3) d1 <- data.frame(z = 1:60); d1$y <- 2 + 0.5 * d1$z + rnorm(60, sd = 0.3) d2 <- data.frame(z = 61:100) d2$y <- 2 + 0.5 * d2$z + rnorm(40, sd = 0.3) + c(rep(0, 20), rep(1, 20)) chart <- edetect_regression(y ~ z, phase1 = d1, phase2 = d2, arl = 200) edetect_alarm(chart)set.seed(3) d1 <- data.frame(z = 1:60); d1$y <- 2 + 0.5 * d1$z + rnorm(60, sd = 0.3) d2 <- data.frame(z = 61:100) d2$y <- 2 + 0.5 * d2$z + rnorm(40, sd = 0.3) + c(rep(0, 20), rep(1, 20)) chart <- edetect_regression(y ~ z, phase1 = d1, phase2 = d2, arl = 200) edetect_alarm(chart)
Everything a reader needs to audit an alarm or its absence: what was assumed (class, centre and its source, bounds or scale, direction), how the detector was built (type, e-value family, mixture), what was observed, the outcome and the software versions.
edetect_report(state)edetect_report(state)
state |
An |
A list of class edetect_report.
design <- edetect_design(arl = 100, class = "bernoulli", center = 0.05) state <- edetect_update(edetect_init(design), x = c(2, 3, 1, 4), n = 50) edetect_report(state)design <- edetect_design(arl = 100, class = "bernoulli", center = 0.05) state <- edetect_update(edetect_init(design), x = c(2, 3, 1, 4), n = 50) edetect_report(state)
Returns a fresh detector with the same design. The history of the previous
run is kept in the runs element of the new object, so that a report can
list every alarm.
edetect_restart(state)edetect_restart(state)
state |
An |
A new edetect_chart.
design <- edetect_design(arl = 20, class = "subgaussian", center = 0, sigma = 1) state <- suppressWarnings(edetect_update(edetect_init(design), c(rnorm(5), rnorm(30, 3)))) edetect_alarm(state)$alarm state <- edetect_restart(state) edetect_alarm(state)$alarmdesign <- edetect_design(arl = 20, class = "subgaussian", center = 0, sigma = 1) state <- suppressWarnings(edetect_update(edetect_init(design), c(rnorm(5), rnorm(30, 3)))) edetect_alarm(state)$alarm state <- edetect_restart(state) edetect_alarm(state)$alarm
u chart: nonconformities per unit of exposure
edetect_u(x, n, center = NULL, phase1 = NULL, ...)edetect_u(x, n, center = NULL, phase1 = NULL, ...)
x |
Counts per sample. |
n |
Exposure (area of opportunity) of each sample. |
center |
Pre-change rate per unit exposure; omit to estimate it from |
phase1 |
Optional Phase I data frame with columns |
... |
Passed to |
An edetect_chart.
chart <- edetect_u(x = c(3, 2, 4, 3, 8, 9, 11), n = c(2, 2, 2, 2, 2, 2, 2), center = 1.5, arl = 100) edetect_alarm(chart)chart <- edetect_u(x = c(3, 2, 4, 3, 8, 9, 11), n = c(2, 2, 2, 2, 2, 2, 2), center = 1.5, arl = 100) edetect_alarm(chart)
Feeds one or more Phase II observations, in time order, to the detector. The
first time the statistic reaches the threshold an alarm is recorded; the
detector does not accept further observations after that (see
edetect_restart()).
edetect_update(state, x, n = NULL)edetect_update(state, x, n = NULL)
state |
An |
x |
Numeric vector of observations (values for the |
n |
Subgroup sizes ( |
The updated edetect_chart.
design <- edetect_design(arl = 100, class = "subgaussian", center = 0, sigma = 1) state <- edetect_init(design) set.seed(1) state <- edetect_update(state, c(rnorm(30), rnorm(30, mean = 1.5))) edetect_alarm(state)design <- edetect_design(arl = 100, class = "subgaussian", center = 0, sigma = 1) state <- edetect_init(design) set.seed(1) state <- edetect_update(state, c(rnorm(30), rnorm(30, mean = 1.5))) edetect_alarm(state)
Individual-observation chart for bounded data
edetect_x(x, bounds, center = NULL, phase1 = NULL, ...)edetect_x(x, bounds, center = NULL, phase1 = NULL, ...)
x |
Phase II observations. |
bounds |
Known bounds of the observations. |
center |
Pre-change mean; omit to estimate it from |
phase1 |
Optional Phase I observations. |
... |
Passed to |
An edetect_chart.
set.seed(2) x <- c(runif(40, 0.3, 0.7), runif(40, 0.5, 0.9)) chart <- edetect_x(x, bounds = c(0, 1), center = 0.5, arl = 200) edetect_alarm(chart)set.seed(2) x <- c(runif(40, 0.3, 0.7), runif(40, 0.5, 0.9)) chart <- edetect_x(x, bounds = c(0, 1), center = 0.5, arl = 200) edetect_alarm(chart)
Glance at a detector
## S3 method for class 'edetect_chart' glance(x, ...)## S3 method for class 'edetect_chart' glance(x, ...)
x |
An |
... |
Unused. |
A one-row tibble: class, center, center_source, direction,
type, arl, n_observed, alarm, alarm_time, evidence,
change_estimate.
chart <- edetect_c(x = c(3, 2, 4, 3, 8, 9, 11), center = 3, arl = 100) glance(chart)chart <- edetect_c(x = c(3, 2, 4, 3, 8, 9, 11), center = 3, arl = 100) glance(chart)
One row per observation with the mixed log e-value, the detector evidence (SR or CUSUM type, as designed), the CUSUM-type evidence, the threshold, the running change-point estimate and the alarm flag.
## S3 method for class 'edetect_chart' tidy(x, ...)## S3 method for class 'edetect_chart' tidy(x, ...)
x |
An |
... |
Unused. |
A tibble with columns t, x, n, log_evalue, evidence,
evidence_cusum, threshold, change_estimate, alarm.
chart <- edetect_c(x = c(3, 2, 4, 3, 8, 9, 11), center = 3, arl = 100) tidy(chart)chart <- edetect_c(x = c(3, 2, 4, 3, 8, 9, 11), center = 3, arl = 100) tidy(chart)