| Title: | Combines Changepoint Analysis with 'ggplot2' |
|---|---|
| Description: | A unified, tidy, 'ggplot2'-native interface to changepoint detection in R. A 'cpt_detect()' dispatcher covers fifty methods (penalised and optimal partitioning, multiscale and search methods, nonparametric and kernel methods, Bayesian methods, high-dimensional, functional, covariance and network methods, regression breaks through a formula interface, seasonal-trend decomposition and the classical single-change tests), with distribution families for counts, binary outcomes and waiting times, missing-value handling, grouped data, and constraints on locations and segment lengths. Every result is the same 'ggcpt' object, in one verified location convention, with 'broom'-style tidy/glance/augment methods, 'autoplot()' and composable 'ggproto' layers. Around detection: effect sizes, a test for a change at a date fixed in advance, tests for a change anywhere, confidence intervals, post-detection tests, selection of the number of changes, assumption checks and goodness of fit, robustness to the noise model, stability, consensus and influence diagnostics, supervised detection, sequential monitoring, power and study design, benchmarks, reports and an export under a documented 'JSON' schema. What each engine does (its runtime, whether its answer survives a change of units or a reversal of time, its false positives by noise regime and data type, its false alarms on pure noise) and the calibration of the package's own intervals and tests are measured and shipped as data, and 'cpt_recommend()' chooses from those measurements. 'cpt_register_method()' brings external and non-CRAN detectors into the same grammar. |
| Authors: | Youzhi Yu [aut, cre] |
| Maintainer: | Youzhi Yu <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 0.6.0 |
| Built: | 2026-10-12 23:37:06 UTC |
| Source: | https://github.com/pursuitofdatascience/ggchangepoint |
Every observation at which a sequential monitor crossed its threshold, in
the order they fired. A monitor that never fired returns a zero-row tibble
rather than NULL, so the result is always safe to rbind() or
plot.
alarms(x, ...) ## S3 method for class 'ggcpt_monitor' alarms(x, ...)alarms(x, ...) ## S3 method for class 'ggcpt_monitor' alarms(x, ...)
x |
A |
... |
Ignored. |
A tibble with one row per alarm: time (the observation at
which it fired, counted from the first one fed to the monitor),
statistic and threshold.
cpt_monitor(), cpt_delay().
set.seed(2026) mon <- cpt_monitor("edetector", baseline = rnorm(100)) mon <- cpt_update(mon, c(rnorm(50), rnorm(50, 3))) alarms(mon)set.seed(2026) mon <- cpt_monitor("edetector", baseline = rnorm(100)) mon <- cpt_update(mon, c(rnorm(50), rnorm(50, 3))) alarms(mon)
Adds alternating shaded rectangles to highlight segments between changepoints.
annotate_segments(cp, n, fill = c("grey90", "white"), alpha = 0.5, ...)annotate_segments(cp, n, fill = c("grey90", "white"), alpha = 0.5, ...)
cp |
Changepoint indices (including 0 and n). |
n |
Length of the series. |
fill |
Colors for alternating segments. Defaults to c("grey90", "white"). |
alpha |
Alpha for fill. Defaults to 0.5. |
... |
Additional arguments passed to |
A list of ggplot annotations.
Other result class:
as_cpt_series(),
as_ggcpt(),
as_json(),
cpt_annotations(),
cpt_export(),
cpt_verify(),
ggchangepoint-conditions,
is_ggcpt(),
new_ggcpt(),
print.ggcpt()
library(ggplot2) set.seed(2026) fit <- cpt_detect(c(rnorm(50), rnorm(50, 4)), method = "pelt") ggplot(fit$data, aes(index, value)) + annotate_segments(fit$changepoints$cp, n = nrow(fit$data)) + geom_line()library(ggplot2) set.seed(2026) fit <- cpt_detect(c(rnorm(50), rnorm(50, 4)), method = "pelt") ggplot(fit$data, aes(index, value)) + annotate_segments(fit$changepoints$cp, n = nrow(fit$data)) + geom_line()
Turns a plain ground-truth changepoint set (the kind
cpt_metrics() takes) into labelled regions, so one
annotation can drive both the metric and the supervised machinery. Each
true changepoint becomes a "one_change" region of width
2 * margin + 1, and the stretches between them become
"no_change" regions.
as_cpt_labels(truth, n, margin = 5, negatives = TRUE, series = NA_character_)as_cpt_labels(truth, n, margin = 5, negatives = TRUE, series = NA_character_)
truth |
Integer vector of true changepoint positions. |
n |
Series length. |
margin |
Half-width of the positive regions. Defaults to |
negatives |
Add the |
series |
Optional series identifier. |
A cpt_labels tibble.
as_cpt_labels(c(50, 120), n = 200)as_cpt_labels(c(50, 120), n = 200)
Detection itself runs on positions (every wrapped engine assumes an
equally spaced sequence), but real series carry dates, and reporting a
changepoint as "index 147" when the data are monthly rainfall is an
unnecessary translation step for the user. as_cpt_series() is the
one place that separates the two: it pulls the numeric values out of a
ts, xts, zoo, tsibble or data frame and
returns the time index alongside them, so cpt_detect() can
detect on positions and report on dates.
as_cpt_series(x, index = NULL, check_regular = TRUE)as_cpt_series(x, index = NULL, check_regular = TRUE)
x |
A numeric vector or matrix, or a |
index |
Optional explicit index, one value per observation. Overrides
any index carried by |
check_regular |
Warn when the index is not equally spaced? Defaults
to |
A list with components values (a numeric vector, or a
matrix for multivariate input), index (the time index, or
NULL when there is none), index_label (a name for the
x axis) and frequency (the seasonal frequency a ts
carried, or NULL; cpt_detect() hands this to
the engines that need one, such as bfast_wrapper()).
Other result class:
annotate_segments(),
as_ggcpt(),
as_json(),
cpt_annotations(),
cpt_export(),
cpt_verify(),
ggchangepoint-conditions,
is_ggcpt(),
new_ggcpt(),
print.ggcpt()
as_cpt_series(1:10)$index s <- as_cpt_series(1:10, index = as.Date("2020-01-01") + 0:9) s$indexas_cpt_series(1:10)$index s <- as_cpt_series(1:10, index = as.Date("2020-01-01") + 0:9) s$index
Wraps a set of changepoint locations (from a detector this package does
not wrap, a Python tool called through reticulate, a neural
detector, a published paper's reported breaks, or an analyst's own
annotations) into a first-class ggcpt object. Everything built on
the ggcpt contract then applies: autoplot(), the composable
geoms, tidy()/glance()/augment(),
cpt_metrics(), cpt_consensus(),
cpt_report().
as_ggcpt( cp, x, fitted = NULL, method = "custom", change_in = "mean", ci = NULL, regions = NULL, penalty = NULL, cp_convention = c("left", "right"), index = NULL, fit = NULL, extra = NULL )as_ggcpt( cp, x, fitted = NULL, method = "custom", change_in = "mean", ci = NULL, regions = NULL, penalty = NULL, cp_convention = c("left", "right"), index = NULL, fit = NULL, extra = NULL )
cp |
Integer vector of changepoint locations. Out-of-range,
duplicated and missing values are dropped and the result is sorted,
the same contract every built-in wrapper is held to. But unlike a
wrapper, which is normalising an engine's output, this function is
given yours, so anything it drops it warns about, with the
values and the range they had to fall in. A fractional index is
included in that: it is truncated rather than rounded, which makes
|
x |
The series the changepoints refer to: a numeric vector, or a matrix/data frame (rows are time points) for a multivariate result. A one-column matrix or data frame is read as a univariate series. |
fitted |
Optional length- |
method |
Method label. Defaults to |
change_in |
What the changepoints are changes in. Defaults to
|
ci |
Optional two-column matrix or data frame of location confidence
intervals, one row per changepoint, giving lower and upper bounds as
positions in the same |
regions |
Optional two-column matrix or data frame of significance
regions ( |
penalty |
Optional penalty descriptor: a number, a string, or a list
with |
cp_convention |
|
index |
Optional time index, one value per observation. |
fit |
Optional raw upstream object to carry along. |
extra |
Optional named list of per-changepoint columns, each of the
same length as |
A ggcpt object, with the same components as any
detector in the package returns (see new_ggcpt()
for the full list, and cpt_detect() for the summary).
cpt_register_method() to make
cpt_detect() dispatch to an external detector by name.
Other result class:
annotate_segments(),
as_cpt_series(),
as_json(),
cpt_annotations(),
cpt_export(),
cpt_verify(),
ggchangepoint-conditions,
is_ggcpt(),
new_ggcpt(),
print.ggcpt()
set.seed(2026) x <- c(rnorm(60), rnorm(60, 4)) fit <- as_ggcpt(c(60), x, method = "my_detector") fit tidy(fit)set.seed(2026) x <- c(rnorm(60), rnorm(60, 4)) fit <- as_ggcpt(c(60), x, method = "my_detector") fit tidy(fit)
The whole result as JSON, under a documented and versioned schema, for software that consumes changepoint results rather than a person reading them.
as_json(x, ...) ## S3 method for class 'ggcpt' as_json(x, pretty = TRUE, data = TRUE, assumptions = TRUE, digits = NA, ...) ## Default S3 method: as_json(x, ...)as_json(x, ...) ## S3 method for class 'ggcpt' as_json(x, pretty = TRUE, data = TRUE, assumptions = TRUE, digits = NA, ...) ## Default S3 method: as_json(x, ...)
x |
A |
... |
Ignored. |
pretty |
Indent the output? Defaults to |
data |
Include the series itself ( |
assumptions |
Include |
digits |
Significant digits for numbers. Defaults to |
A single string of class "json".
One object with these fields. Every field is always present; one that
does not apply is null, so a reader never has to test for a key.
schema, schema_version
"ggchangepoint.ggcpt"
and the version, "1.0.0".
method, engine, engine_version,
ggchangepoint_version, r_version, created
what produced the result, and when (ISO 8601).
change_in, family
what was detected, and the distribution family if one was asked for.
penalty{"type", "value"}.
cp_convention"left": a changepoint is the last
observation of its segment.
nthe series length.
index{"class", "label", "tz"} of the time
index, or null. Dates are written as ISO 8601 strings and
timestamps with their offset; tz is a timestamp index's time
zone (null otherwise).
changepointsan array of objects, one per changepoint:
cp (position) and cp_value, with cp_index when
there is an index, and every engine-specific column
(ci_lower, ci_upper, posterior_prob, ...).
segmentsseg_id, start, end,
n, param_estimate.
regions, coefficients, constraints
the
optional slots, as arrays of objects (or an object), or null.
diagnosticsresidual_dependence (Ljung-Box
p_value, lag, acf1), na_omitted and
expected_false_positives where recorded.
assumptionsthe cpt_assumptions() rows, or
null.
callthe call that made the result, as text.
data{"index", "value", "fitted",
"coordinates"} arrays, or null. coordinates is an
object with one array per coordinate of a multivariate result
(null for a single series), whose first is value.
cpt_export() to write a file,
cpt_import() to read one back,
cpt_report(format = "json").
Other result class:
annotate_segments(),
as_cpt_series(),
as_ggcpt(),
cpt_annotations(),
cpt_export(),
cpt_verify(),
ggchangepoint-conditions,
is_ggcpt(),
new_ggcpt(),
print.ggcpt()
set.seed(1) fit <- cpt_detect(c(rnorm(50), rnorm(50, 3)), method = "pelt") cat(as_json(fit, data = FALSE))set.seed(1) fit <- cpt_detect(c(rnorm(50), rnorm(50, 3)), method = "pelt") cat(as_json(fit, data = FALSE))
Returns the original data with added columns: seg_id, .fitted,
.resid, and is_changepoint.
## S3 method for class 'ggcpt' augment(x, ...)## S3 method for class 'ggcpt' augment(x, ...)
x |
A |
... |
Additional arguments (ignored). |
For a multivariate result every coordinate is returned, but the
changepoints are shared across them, so seg_id and
is_changepoint apply to the whole row. Each coordinate also gets
its own .fitted_<name> and .resid_<name> (its segment
means and residuals), while .fitted and
.resid describe the univariate series the result
carries: $data$value, the same series
$segments$param_estimate summarises, so .resid is always
value - .fitted. For most multivariate engines that series is
the first coordinate; fmean, fcov, kwc and
fabisearch store the cross-sectional mean rowMeans()
instead, and for those .fitted/.resid describe that mean
rather than any one column. Either way the two columns agree with each
other, which is what makes .resid a residual. When an engine
supplies its own fitted signal that signal is used for .fitted in
place of the segment means, and rides along in a fitted column of
its own, so for those engines the two columns agree. The engines that
do this are exactly the ones cpt_methods() marks in its
fitted column: smuce, hsmuce, cpop,
bcp, bocpd, beast, decafs,
segmented, envcpt, mcp and bfast; a
formula fit carries its piecewise regression's fitted values the same
way.
A tibble with one row per observation: the data as the result
carries it, plus four added columns. The data half depends on the
result: index and value for a univariate one,
index plus one column per coordinate (named as the
input's columns were) for a multivariate one, and an extra
fitted column for the engines that supply their own fitted
signal. The added four are always the same:
seg_idwhich segment the observation falls in, counting from 1.
.fittedthe segment's param_estimate: the
segment mean, for every method in the package, or the
engine's own fitted signal where there is one. See the details
below for the multivariate case.
.residvalue - .fitted, against the
univariate series the result carries.
is_changepointTRUE at each detected
location, under the result's cp_convention.
Measured on a pelt fit the columns are index,
value, seg_id, .fitted, .resid,
is_changepoint.
set.seed(2026) fit <- cpt_detect(c(rnorm(60), rnorm(60, 3)), method = "pelt") head(augment(fit))set.seed(2026) fit <- cpt_detect(c(rnorm(60), rnorm(60, 3)), method = "pelt") head(augment(fit))
Renders a changepoint detection result as a ggplot. The raw series is drawn
as a line (with optional points), changepoints are shown as vertical lines,
and (optionally) fitted segment levels, the engine's fitted signal, and
changepoint-location confidence intervals are overlaid. Multivariate
results (from ecp, inspect, geomcp, ...) are drawn as
faceted small-multiples with shared changepoint rules.
## S3 method for class 'ggcpt' autoplot( object, show_segments = FALSE, show_ci = FALSE, show_fit = FALSE, show_regions = NULL, cptline_alpha = 1, cptline_color = "blue", cptline_type = "solid", cptline_linewidth = 0.5, show_points = NULL, show_line = TRUE, index = NULL, labels = NULL, type = c("series", "statistic", "path", "scale_space", "diagnostics"), ... )## S3 method for class 'ggcpt' autoplot( object, show_segments = FALSE, show_ci = FALSE, show_fit = FALSE, show_regions = NULL, cptline_alpha = 1, cptline_color = "blue", cptline_type = "solid", cptline_linewidth = 0.5, show_points = NULL, show_line = TRUE, index = NULL, labels = NULL, type = c("series", "statistic", "path", "scale_space", "diagnostics"), ... )
object |
A |
show_segments |
Logical. Whether to draw the fitted segment means.
Defaults to |
show_ci |
Logical. Whether to draw confidence intervals for
changepoint locations, when the engine provides them (columns
|
show_fit |
Logical. Whether to draw the engine's fitted signal (the
|
show_regions |
Logical. Whether to shade the significance regions an
interval-valued method returns (the |
cptline_alpha |
Alpha for changepoint lines. Defaults to |
cptline_color |
Color for changepoint lines. Defaults to |
cptline_type |
Linetype for changepoint lines. Defaults to |
cptline_linewidth |
Linewidth for changepoint lines. Defaults to |
show_points |
Logical. Whether to draw data points. Auto-off above 500 obs. |
show_line |
Logical. Whether to draw the line. Defaults to |
index |
Optional vector of x-axis values (e.g. dates) of the same
length as the series. Defaults to the time index carried by the result
(see the |
labels |
Optional |
type |
Which view to draw. |
... |
Unknown arguments are ignored with a warning, except when
|
A ggplot object.
ggcpt_plot_methods for the base plot()
methods that delegate here, and theme_ggcpt() and
geom_changepoint() for restyling and re-assembling the
layers by hand.
set.seed(2026) fit <- cpt_detect(c(rnorm(60), rnorm(60, 3), rnorm(60)), method = "pelt") ggplot2::autoplot(fit) ggplot2::autoplot(fit, type = "diagnostics") # a dated series draws its dates dated <- cpt_detect(Nile, method = "pelt", change_in = "meanvar") ggplot2::autoplot(dated)set.seed(2026) fit <- cpt_detect(c(rnorm(60), rnorm(60, 3), rnorm(60)), method = "pelt") ggplot2::autoplot(fit) ggplot2::autoplot(fit, type = "diagnostics") # a dated series draws its dates dated <- cpt_detect(Nile, method = "pelt", change_in = "meanvar") ggplot2::autoplot(dated)
Wraps bcp::bcp(), the MCMC implementation (Erdman and Emerson, 2007)
of the Barry and Hartigan (1993) product partition model. The engine
returns a posterior probability of a changepoint at every location;
locations whose posterior probability reaches prob_threshold are
reported as changepoints, and the full probability profile is kept so that
ggcpt_posterior() can draw the classic two-panel posterior
plot.
bcp_wrapper(x, prob_threshold = 0.5, burnin = 50, mcmc = 500, seed = NULL, ...)bcp_wrapper(x, prob_threshold = 0.5, burnin = 50, mcmc = 500, seed = NULL, ...)
x |
A numeric vector. |
prob_threshold |
Posterior probability cutoff in |
burnin |
Number of burn-in MCMC iterations. Defaults to |
mcmc |
Number of post-burn-in MCMC iterations. Defaults to |
seed |
Optional seed for reproducibility of the MCMC run. The seed
is scoped to this call: |
... |
Additional arguments passed to |
A ggcpt object. The changepoints tibble carries a
posterior_prob column, and the data tibble carries the
posterior mean in its fitted column.
Barry D, Hartigan JA (1993). “A Bayesian analysis for change point problems.” Journal of the American Statistical Association, 88(421), 309–319.
Erdman C, Emerson JW (2007). “bcp: An R package for performing a Bayesian analysis of change point problems.” Journal of Statistical Software, 23(3), 1–13.
Other changepoint engines:
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
res <- bcp_wrapper(c(rnorm(60), rnorm(60, 4)), seed = 2026) res$changepoints ggcpt_posterior(res)res <- bcp_wrapper(c(rnorm(60), rnorm(60, 4)), seed = 2026) res$changepoints ggcpt_posterior(res)
Wraps Rbeast::beast() (Zhao et al., 2019), a Bayesian
model-averaging ensemble that estimates the number and location of trend
changepoints together with their posterior occurrence probabilities.
Locations whose posterior probability reaches prob_threshold are
reported; the probability profile renders via
ggcpt_posterior().
beast_wrapper(x, prob_threshold = 0.5, seed = NULL, ...)beast_wrapper(x, prob_threshold = 0.5, seed = NULL, ...)
x |
A numeric vector (treated as a non-seasonal series). |
prob_threshold |
Posterior probability cutoff in |
seed |
Optional seed for the engine's MCMC sampler (passed to
|
... |
Additional arguments passed to |
A ggcpt object. The changepoints tibble carries
posterior_prob, and the data tibble carries the posterior
mean trend in its fitted column.
Zhao K, Wulder MA, Hu T, Bright R, Wu Q, Qin H, Li Y, Toman E, Mallick B, Zhang X, Brown M (2019). “Detecting change-point, trend, and seasonality in satellite time series data to track abrupt changes and nonlinear dynamics: A Bayesian ensemble algorithm.” Remote Sensing of Environment, 232, 111181.
Other changepoint engines:
bcp_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
# try(): Rbeast intermittently returns an all-NaN fit and the condition # can persist for a session, so a check must not fail on it; the # wrapper reports it by name when it happens. res <- try(beast_wrapper(c(rnorm(60), rnorm(60, 4)), seed = 2026), silent = TRUE) if (!inherits(res, "try-error")) res$changepoints# try(): Rbeast intermittently returns an all-NaN fit and the condition # can persist for a session, so a check must not fail on it; the # wrapper reports it by name when it happens. res <- try(beast_wrapper(c(rnorm(60), rnorm(60, 4)), seed = 2026), silent = TRUE) if (!inherits(res, "try-error")) res$changepoints
Wraps the bfast family (Verbesselt et al.), the standard tool in remote sensing and land-cover monitoring. BFAST decomposes a seasonal series into trend and seasonal components and detects breaks in each separately, which is the right question for satellite time series where a shift in phenology and a shift in level mean different things.
bfast_wrapper( x, frequency = 12, change_in = c("mean", "slope", "seasonality"), h = 0.15, season = c("harmonic", "dummy", "none"), max_iter = 5, ... )bfast_wrapper( x, frequency = 12, change_in = c("mean", "slope", "seasonality"), h = 0.15, season = c("harmonic", "dummy", "none"), max_iter = 5, ... )
x |
A numeric vector, or a |
frequency |
Observations per season, used when |
change_in |
Which component's breaks to report: |
h |
Minimal segment size as a fraction of the series. Defaults to
|
season |
Seasonal model: |
max_iter |
Maximum iterations of the trend/season loop. Defaults to
|
... |
Additional arguments passed to |
A ggcpt object whose fitted column holds the
estimated trend component (so autoplot(show_fit = TRUE) draws it)
and whose changepoints carry ci_lower/ci_upper from
strucchange's break-date intervals when available.
Verbesselt J, Hyndman R, Newnham G, Culvenor D (2010). “Detecting trend and seasonal changes in satellite image time series.” Remote Sensing of Environment, 114(1), 106–115. doi:10.1016/j.rse.2009.08.014.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) season <- rep(sin(seq(0, 2 * pi, length.out = 12)), 10) y <- stats::ts(c(rnorm(60, 1), rnorm(60, 5)) + season, frequency = 12, start = c(2000, 1)) bfast_wrapper(y)set.seed(2026) season <- rep(sin(seq(0, 2 * pi, length.out = 12)), 10) y <- stats::ts(c(rnorm(60, 1), rnorm(60, 5)) + season, frequency = 12, start = c(2000, 1)) bfast_wrapper(y)
Wraps binsegRcpp::binseg() (Hocking): a C++ binary segmentation
that runs in for the best case and supports several
loss functions, including ones no other engine here offers (Poisson,
). It is the package's performance path for binary
segmentation on long series, and it returns the whole nested family of
segmentations, so it also feeds cpt_solution_path().
binsegrcpp_wrapper( x, change_in = c("mean", "meanvar"), distribution = NULL, max_segments = NULL, n_segments = NULL, min_segment_length = NULL )binsegrcpp_wrapper( x, change_in = c("mean", "meanvar"), distribution = NULL, max_segments = NULL, n_segments = NULL, min_segment_length = NULL )
x |
A numeric vector. |
change_in |
|
distribution |
Loss function, overriding the mapping from
|
max_segments |
Largest number of segments searched. Defaults to
|
n_segments |
Number of segments to report. When |
min_segment_length |
Minimum segment length. Defaults to |
A ggcpt object.
Hocking TD (2024). “Finite sample complexity analysis of binary segmentation.” arXiv preprint arXiv:2410.08654. doi:10.48550/arXiv.2410.08654.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) binsegrcpp_wrapper(c(rnorm(100), rnorm(100, 3)))set.seed(2026) binsegrcpp_wrapper(c(rnorm(100), rnorm(100, 3)))
Wraps ocp::onlineCPD(), an implementation of Bayesian Online
Changepoint Detection (Adams and MacKay, 2007). BOCPD recursively updates
a posterior over the current run length (time since the last
change); the maximum a posteriori set of changepoints is reported, and the
full run-length posterior is kept so that ggcpt_runlength()
can draw the signature run-length heatmap.
bocpd_wrapper(x, hazard = 100, ...)bocpd_wrapper(x, hazard = 100, ...)
x |
A numeric vector. |
hazard |
The |
... |
Additional arguments passed to |
A ggcpt object with the MAP changepoint set. The full
ocp fit (including the run-length posterior) is kept in
$fit.
Adams RP, MacKay DJ (2007). “Bayesian online changepoint detection.” arXiv preprint arXiv:0710.3742.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
res <- bocpd_wrapper(c(rnorm(60), rnorm(60, 4))) res$changepoints ggcpt_runlength(res)res <- bocpd_wrapper(c(rnorm(60), rnorm(60, 4))) res$changepoints ggcpt_runlength(res)
Wraps cpm::processStream() (Ross, 2015) for distribution-free
sequential changepoint detection via repeated two-sample tests
(Mann-Whitney for location, Mood for scale, Lepage, Kolmogorov-Smirnov and
Cramer-von-Mises for general changes, and parametric Student/Bartlett/GLR
variants). Although the engine is designed for streams, it is run here
over the full series in one pass, mimicking online monitoring with average
run length arl0.
cpm_wrapper(x, cpm_type = "Mann-Whitney", arl0 = NULL, startup = 20, ...)cpm_wrapper(x, cpm_type = "Mann-Whitney", arl0 = NULL, startup = 20, ...)
x |
A numeric vector. |
cpm_type |
Test statistic, passed to |
arl0 |
Target in-control average run length (how many observations,
on average, before a false alarm). cpm
ships thresholds only for a fixed grid (100, 200, 300, 370, 400, 500,
600, 700, 800, 900, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000,
9000, 10000, 20000, 30000, 40000 and 50000), and any other value is
refused, because the engine answers it by printing an error and
reporting no changepoints. The grid is the same for every
When |
startup |
Number of observations after each restart before monitoring
begins. Defaults to |
... |
Additional arguments passed to |
A ggcpt object. The changepoints tibble carries a
detection_time column: the index at which the sequential test
flagged each change (always later than the estimated location).
Ross GJ (2015). “Parametric and nonparametric sequential change detection in R: The cpm package.” Journal of Statistical Software, 66(3), 1–20.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
res <- cpm_wrapper(c(rnorm(100), rnorm(100, 3))) res$changepointsres <- cpm_wrapper(c(rnorm(100), rnorm(100, 3))) res$changepoints
Wraps cpop::cpop() (Fearnhead, Maidstone and Letchford, 2019;
Fearnhead and Grose, 2024): exact penalised estimation of a
continuous piecewise-linear mean via dynamic programming with
functional pruning. This is the engine behind
cpt_detect(change_in = "slope"). The fitted broken line is stored
in the fitted column and renders via
autoplot(show_fit = TRUE).
cpop_wrapper(x, penalty = NULL, sd = NULL, ...)cpop_wrapper(x, penalty = NULL, sd = NULL, ...)
x |
A numeric vector. |
penalty |
Penalty for adding a changepoint. Defaults to
|
sd |
Noise standard deviation; when |
... |
Additional arguments passed to |
A ggcpt object with change_in = "slope". For a
continuous fit the reported location is the kink point itself.
Fearnhead P, Maidstone R, Letchford A (2019). “Detecting changes in slope with an L0 penalty.” Journal of Computational and Graphical Statistics, 28(2), 265–275.
Fearnhead P, Grose D (2024). “cpop: Detecting changes in piecewise-linear signals.” Journal of Statistical Software, 109(7), 1–30.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) y <- cumsum(c(rep(0.3, 100), rep(-0.4, 100))) + rnorm(200) res <- cpop_wrapper(y) res$changepoints ggplot2::autoplot(res, show_fit = TRUE)set.seed(2026) y <- cumsum(c(rep(0.3, 100), rep(-0.4, 100))) + rnorm(200) res <- cpop_wrapper(y) res$changepoints ggplot2::autoplot(res, show_fit = TRUE)
Joins a table of real-world events to a detection result and reports all
three outcomes: changepoints an event explains, changepoints no event
explains, and events no changepoint found. Matching reuses the same
tolerance rule as cpt_metrics() and
cpt_consensus(), so the package has one notion of "close
enough" throughout.
cpt_annotate_events( object, events, location = NULL, label = NULL, tolerance = 5 ) ## S3 method for class 'ggcpt_events' print(x, ...) ## S3 method for class 'ggcpt_events' tidy(x, ...) ## S3 method for class 'ggcpt_events' autoplot(object, repel = NULL, ...)cpt_annotate_events( object, events, location = NULL, label = NULL, tolerance = 5 ) ## S3 method for class 'ggcpt_events' print(x, ...) ## S3 method for class 'ggcpt_events' tidy(x, ...) ## S3 method for class 'ggcpt_events' autoplot(object, repel = NULL, ...)
object |
A |
events |
A data frame of events with a location column and a label
column. The location may be on the position scale or, when the result
carries a time index, on the index scale (dates, say); which one is
detected automatically from the column's type and reported. An event
whose location cannot be placed on the series (a missing value, text
that is not a number, or a date string against a |
location |
Name of the location column. Defaults to the first column whose type matches the result's index (or the first numeric column). |
label |
Name of the label column. Defaults to the first character or factor column. |
tolerance |
Matching window in positions. Defaults to |
x |
A |
... |
Ignored. |
repel |
Use ggrepel for the event labels? Defaults to
|
A ggcpt_events object: a list with
matchedone row per matched pair: cp,
event, event_value (the event's own location, on
the index scale when it was given as one), event_position
(that location as a position in the series) and distance.
unexplaineddetected changepoints with no event
(cp).
undetectedevents with no changepoint
(event, event_value, event_position).
matched and unexplained carry cp_index, the
changepoint on the original scale, when (and only when) the result
carries a time index, so "cp_index" %in% names(x) is the
test for it.
tidy() flattens those three slots into one table with
a status column, and the row count is therefore the number of
changepoints plus the number of events, not either one alone.
The three values are
"matched" (a pair: both cp and event filled,
with distance), "unexplained_changepoint" (a
changepoint with no event: cp filled, event and
distance NA) and "undetected_event" (an event
with no changepoint: event and position filled,
cp and distance NA).
Filter on status, not on is.na(cp). An
"unexplained_changepoint" row has a non-missing cp, so
subset(tidy(x), !is.na(cp)) returns the matched pairs
and the unexplained changepoints, which is the natural
mistake to make, and it silently overstates how many changepoints an
event explains.
With print(), tidy() and autoplot().
geom_cpt_event(), cpt_report().
set.seed(2026) x <- c(rnorm(60), rnorm(60, 4)) dates <- as.Date("2020-01-01") + 0:119 fit <- cpt_detect(x, method = "pelt", index = dates) events <- data.frame(when = as.Date(c("2020-03-01", "2020-04-15")), what = c("policy change", "supply shock")) cpt_annotate_events(fit, events)set.seed(2026) x <- c(rnorm(60), rnorm(60, 4)) dates <- as.Date("2020-01-01") + 0:119 fit <- cpt_detect(x, method = "pelt", index = dates) events <- data.frame(when = as.Date(c("2020-03-01", "2020-04-15")), what = c("policy change", "supply shock")) cpt_annotate_events(fit, events)
Returns the annotation sets of a dataset one row per (annotator, changepoint), so the disagreement between human annotators is visible instead of averaged away.
cpt_annotations(dataset)cpt_annotations(dataset)
dataset |
A dataset in the |
A tibble with dataset, annotator and cp.
Other result class:
annotate_segments(),
as_cpt_series(),
as_ggcpt(),
as_json(),
cpt_export(),
cpt_verify(),
ggchangepoint-conditions,
is_ggcpt(),
new_ggcpt(),
print.ggcpt()
cpt_annotations(cpt_datasets(n = 200, names = "step"))cpt_annotations(cpt_datasets(n = 200, names = "step"))
A short report on whether the result's assumptions look violated for this series, what that does to the answer, and what would model it. It reports and does not act: every automatic correction measured trades true changepoints for false ones, and which side of that trade matters is the analyst's decision.
cpt_assumptions(fit, lag = NULL) ## S3 method for class 'ggcpt_assumptions' print(x, ...) ## S3 method for class 'ggcpt_assumptions' tidy(x, ...)cpt_assumptions(fit, lag = NULL) ## S3 method for class 'ggcpt_assumptions' print(x, ...) ## S3 method for class 'ggcpt_assumptions' tidy(x, ...)
fit |
A |
lag |
Lag for the Ljung-Box test. Defaults to |
x |
A |
... |
Ignored. |
A ggcpt_assumptions tibble with one row per check:
component, value, flag (TRUE when the check
raises a concern), detail and advice. The components:
residual_dependenceLjung-Box p-value on the
within-segment residuals (and their lag-1 autocorrelation in
detail). Flagged below 0.05. Autocorrelated noise is the
commonest reason for spurious changepoints.
scale_sensitivitythe noise standard deviation, flagged when the engine's answer depends on the data's units (measured) and the noise is far from unit scale.
expected_false_positiveshow many changepoints the
engine is expected to report on this much pure noise: n /
arl0 for cpm, and the measured null-size table otherwise.
Flagged above one.
count_plausibilityreported changepoints per hundred
observations, flagged above one: more than n / 100 is more
often misconfiguration than a finding.
data_typewhat the series looks like (continuous, counts, binary, proportions), flagged when a Gaussian cost is fitted to non-Gaussian data.
cpt_report(), which prints this;
cpt_robustness() for the answer under other noise models.
Other inference:
cpt_attribute_event(),
cpt_effect(),
cpt_gof(),
cpt_null_power(),
cpt_robustness(),
cpt_test_at(),
cpt_test_null()
set.seed(1) ar <- as.numeric(arima.sim(list(ar = 0.7), 300)) cpt_assumptions(cpt_detect(ar, method = "pelt"))set.seed(1) ar <- as.numeric(arima.sim(list(ar = 0.7), 300)) cpt_assumptions(cpt_detect(ar, method = "pelt"))
The mirror of cpt_test_at(). A detector found a change on
14 March and something is known to have happened on 1 March: is that the
same event? The detection's confidence interval answers it: an event
inside the interval is consistent with being the change, one outside is
not.
cpt_attribute_event(fit, event, level = 0.95, ...)cpt_attribute_event(fit, event, level = 0.95, ...)
fit |
A |
event |
One or more event locations: positions, values of the fit's
index, or a |
level |
Confidence level of the interval. Defaults to |
... |
Further arguments for |
A tibble with one row per event: event,
event_position, the nearest changepoint cp (and
cp_index), its interval ci_lower/ci_upper,
distance (positions from the changepoint to the event),
inside and a plain-language verdict.
Other inference:
cpt_assumptions(),
cpt_effect(),
cpt_gof(),
cpt_null_power(),
cpt_robustness(),
cpt_test_at(),
cpt_test_null()
set.seed(1) dates <- as.Date("2026-01-01") + 0:119 fit <- cpt_detect(c(rnorm(60), rnorm(60, 3)), method = "strucchange", index = dates) cpt_attribute_event(fit, as.Date(c("2026-02-28", "2026-04-10")))set.seed(1) dates <- as.Date("2026-01-01") + 0:119 fit <- cpt_detect(c(rnorm(60), rnorm(60, 3)), method = "strucchange", index = dates) cpt_attribute_event(fit, as.Date(c("2026-02-28", "2026-04-10")))
Runs one detector over every series in a collection: the panel-data loop
that methodological and applied work both need constantly. Accepts a
matrix/data frame (one column per series) or a named list of numeric
vectors. Honours future::plan() for parallel execution when the
future.apply package is available, with parallel-safe RNG.
cpt_batch( x, method = "pelt", change_in = "mean", index = NULL, seed = NULL, keep_fit = TRUE, ... ) ## S3 method for class 'ggcpt_batch' print(x, ...) ## S3 method for class 'ggcpt_batch' tidy(x, ...) ## S3 method for class 'ggcpt_batch' autoplot(object, ...)cpt_batch( x, method = "pelt", change_in = "mean", index = NULL, seed = NULL, keep_fit = TRUE, ... ) ## S3 method for class 'ggcpt_batch' print(x, ...) ## S3 method for class 'ggcpt_batch' tidy(x, ...) ## S3 method for class 'ggcpt_batch' autoplot(object, ...)
x |
For |
method |
Detection method, passed to |
change_in |
What to detect change in, passed to
|
index |
Optional time index shared by every series in the panel (a
vector of dates, say), or a named list of one index per series. A list
has to cover every series, with indices of one type, because
|
seed |
Optional seed for reproducible parallel execution (passed to
|
keep_fit |
Keep each engine's raw fit in |
... |
Additional arguments passed to every |
object |
A |
A ggcpt_batch object: a tibble with one row per series and
columns series, n_changepoints, changepoints (a
list-column of tidy tibbles), and result (a list-column of
ggcpt objects). Methods: print(), tidy() (one row
per changepoint across all series, with columns series,
cp and cp_value), and autoplot() (faceted
small-multiples with each series' changepoints).
set.seed(2026) X <- cbind(a = c(rnorm(60), rnorm(60, 4)), b = rnorm(120)) batch <- cpt_batch(X, method = "pelt") batch tidy(batch) ggplot2::autoplot(batch)set.seed(2026) X <- cbind(a = c(rnorm(60), rnorm(60, 4)), b = rnorm(120)) batch <- cpt_batch(X, method = "pelt") batch tidy(batch) ggplot2::autoplot(batch)
Runs a grid of methods over a collection of labelled series and scores
every cell with cpt_metrics() (or
cpt_metrics_annotated() when a dataset carries several
annotators). A method that fails on one dataset (its engine errors, is
not installed, or cannot take that series: see
ggchangepoint-conditions) records the message and the grid
continues. Invalid data or arguments, which every method would reject,
stop the benchmark instead, naming the dataset and method, so a mistake
in the call is not reported as a finding about an engine.
cpt_benchmark( datasets, methods = c("pelt", "binseg", "wbs"), metrics = c("covering", "f1"), tolerance = 5, change_in = "mean", parallel = TRUE, progress = TRUE, seed = NULL, ... ) ## S3 method for class 'ggcpt_benchmark' print(x, ...) ## S3 method for class 'ggcpt_benchmark' tidy(x, ...) ## S3 method for class 'ggcpt_benchmark' autoplot( object, plot_type = c("heatmap", "ranks", "critical_difference"), metric = NULL, alpha = 0.05, ... )cpt_benchmark( datasets, methods = c("pelt", "binseg", "wbs"), metrics = c("covering", "f1"), tolerance = 5, change_in = "mean", parallel = TRUE, progress = TRUE, seed = NULL, ... ) ## S3 method for class 'ggcpt_benchmark' print(x, ...) ## S3 method for class 'ggcpt_benchmark' tidy(x, ...) ## S3 method for class 'ggcpt_benchmark' autoplot( object, plot_type = c("heatmap", "ranks", "critical_difference"), metric = NULL, alpha = 0.05, ... )
datasets |
A named list of datasets. Each element is either a plain
numeric vector (no ground truth, so only descriptive columns are filled)
or a list with |
methods |
Character vector of method names. |
metrics |
Which metrics to keep. Defaults to
|
tolerance |
Matching window passed to the metrics. Defaults to
|
change_in |
Passed to every detector. |
parallel |
Use |
progress |
Show a progressr progress bar when that package is
installed and a handler is enabled? Defaults to |
seed |
Optional seed. The seed is scoped to this call:
|
... |
Additional arguments passed to every |
x |
A |
object |
A |
plot_type |
|
metric |
Which metric to plot. Defaults to the first one scored. |
alpha |
Level for the critical distance, in |
A ggcpt_benchmark object: a tibble with one row per
(dataset, method): dataset, method, n,
n_annotators (how many ground-truth sets the dataset supplied),
n_cp, the requested metrics, runtime and error,
with
print(), tidy() and autoplot()
("heatmap", "ranks", "critical_difference").
Rank 1 is best. Each method's mean rank is taken over the datasets, in
the direction the metric calls for: higher is better for
covering, f1, precision, recall and
rand_index; lower for hausdorff,
annotation_error, mae_matched and rmse_matched.
A metric that came back NA takes the worst rank on that
dataset rather than being dropped, so a method that failed there is
penalised for it instead of quietly scoring on a smaller sample; ties
share the average rank.
The bar is the Nemenyi critical distance
for methods over datasets, where is
the Studentised range statistic at divided by
(Demsar, 2006; the constants agree with that paper's
Table 5 to three decimals for ). Two methods
whose mean ranks differ by less than are not distinguished at
that level.
One caveat the diagram cannot show. Nemenyi is a
post-hoc procedure, and the convention is to run it only after a
Friedman test has rejected the null that all methods rank equally.
autoplot() does not run that omnibus test (it draws the
diagram it is asked for), so a gap wider than on a grid where
Friedman would not have rejected is not the significant difference it
looks like. With the handful of datasets cpt_datasets()
supplies, is small and correspondingly wide; read the
diagram as a descriptive summary unless is large enough to
support the test.
van den Burg GJJ, Williams CKI (2020). “An evaluation of change point detection algorithms.” arXiv preprint arXiv:2003.06222. doi:10.48550/arXiv.2003.06222.
Demšar J (2006). “Statistical comparisons of classifiers over multiple data sets.” Journal of Machine Learning Research, 7, 1–30.
cpt_datasets(), cpt_load_tcpd(),
cpt_metrics().
bm <- cpt_benchmark(cpt_datasets(n = 200, seed = 1), methods = c("pelt", "binseg", "amoc"), progress = FALSE) bm ggplot2::autoplot(bm)bm <- cpt_benchmark(cpt_datasets(n = 200, seed = 1), methods = c("pelt", "binseg", "amoc"), progress = FALSE) bm ggplot2::autoplot(bm)
The calibration suite: every guarantee the documentation states that a
simulation can check, with the realised value and its Monte Carlo
standard error. Location intervals are scored for coverage (conditional
on a changepoint landing within 20 positions of the truth), tests for
their size at 5% on data with no change, and monitors for their
in-control run length. The row for cpt_test() at a location the
data chose is there to show what selection_adjusted = FALSE
means: its nominal 5% is not what it delivers.
cpt_calibrationcpt_calibration
A tibble with one row per guarantee and setting:
what is promised, and by which function.
the call that was measured.
the data and the options it was measured on.
"coverage", "size" or "run_length".
the promised value: a confidence level, a test's level or an average run length (for the e-detector, a lower bound).
the measured value.
its Monte Carlo standard error.
replicates that counted (for coverage, those that detected the change).
data-raw/calibration.R.
The calibration article on the package website, https://pursuitofdatascience.github.io/ggchangepoint/articles/calibration.html.
Other measurement tables:
cpt_data_types,
cpt_invariances,
cpt_noise_benchmark,
cpt_null_sizes,
cpt_runtimes
cpt_calibration[, c("call", "nominal", "realised", "mcse")]cpt_calibration[, c("call", "nominal", "realised", "mcse")]
Returns the bibliographic reference(s) for the method behind a
ggcpt result (or a method name), so an analysis can cite the right
methodological paper without leaving R.
cpt_cite(x)cpt_cite(x)
x |
A |
A tibble with columns method and reference,
invisibly; the references are also printed.
cpt_cite("pelt") res <- cpt_detect(c(rnorm(50), rnorm(50, 5)), method = "pelt") cpt_cite(res)cpt_cite("pelt") res <- cpt_detect(c(rnorm(50), rnorm(50, 5)), method = "pelt") cpt_cite(res)
Answers "where could this changepoint be?" for any result, and says which
of four routes it used. show_ci = TRUE in autoplot() works
only for the handful of engines that ship intervals of their own; this
generic covers the rest, and (because the four routes mean genuinely
different things) reports the provenance in a source column
rather than presenting them as interchangeable.
cpt_confint( object, level = 0.95, method = c("auto", "native", "nsp", "bootstrap", "posterior"), B = 200, seed = NULL, ... )cpt_confint( object, level = 0.95, method = c("auto", "native", "nsp", "bootstrap", "posterior"), B = 200, seed = NULL, ... )
object |
A |
level |
Confidence/credible level. Defaults to |
method |
Which route to use:
|
B |
Bootstrap replicates for |
seed |
Optional seed (bootstrap and NSP are both random). The seed
is scoped to this call: |
... |
Passed to |
A tibble with one row per changepoint: cp,
ci_lower, ci_upper, level, source, plus
cp_index/ci_lower_index/ci_upper_index on the
original scale when the result carries a time index, and
n_replicates for method = "bootstrap" (how many
replicates actually contributed a draw for that changepoint).
method = "nsp" returns NA bounds for a changepoint that
falls in no region, which is a finding rather than a failure.
Measured over 120 replicates on a 200-point series with one changepoint
at 100 and a jump of three standard deviations, at a nominal level of
0.95: "bootstrap" on pelt covered 0.992 of the time with
a mean width of 2.2; strucchange's native intervals covered 1.000
at width 4.4; stepR's (smuce) covered 0.992 at width 4.6;
and "posterior" on bcp covered 1.000 at width 157. Every
route is conservative (none under-covers), and the width is
what separates them. The two native routes and the bootstrap are the
ones to quote; see the note on "posterior" above for why its
interval is so much wider.
cpt_test(), cpt_stability(),
nsp_wrapper().
set.seed(2026) x <- c(rnorm(80), rnorm(80, 4)) fit <- cpt_detect(x, method = "pelt") cpt_confint(fit, method = "bootstrap", B = 25, seed = 1)set.seed(2026) x <- c(rnorm(80), rnorm(80, 4)) fit <- cpt_detect(x, method = "pelt") cpt_confint(fit, method = "bootstrap", B = 25, seed = 1)
Runs a set of detectors on one series and reports the locations they agree
on. Two detections count as the same changepoint when they fall within
tolerance of each other, the same tolerance window
cpt_metrics() matches on (van den Burg and Williams, 2020),
so the package has one notion of "close enough" and not two. The
grouping necessarily differs: cpt_metrics() matches two
sets one-to-one, while consensus has to cluster of them, so
detections are swept in order and a new cluster opens as soon as one lies
more than tolerance from the cluster's first member. That cap stops
a chain of near-neighbours merging into one arbitrarily wide cluster.
cpt_consensus( x, methods = c("pelt", "binseg", "amoc"), tolerance = 5, min_votes = "majority", change_in = "mean", index = NULL, seed = NULL, ... ) ## S3 method for class 'ggcpt_consensus' autoplot(object, plot_type = c("series", "agreement"), ...) ## S3 method for class 'ggcpt_consensus' print(x, ...)cpt_consensus( x, methods = c("pelt", "binseg", "amoc"), tolerance = 5, min_votes = "majority", change_in = "mean", index = NULL, seed = NULL, ... ) ## S3 method for class 'ggcpt_consensus' autoplot(object, plot_type = c("series", "agreement"), ...) ## S3 method for class 'ggcpt_consensus' print(x, ...)
x |
A |
methods |
Character vector of method names. A method that fails on
this series (its engine errors or is not installed, or it does not
offer |
tolerance |
Matching window, in positions. Defaults to |
min_votes |
Minimum number of methods that must find a location for
it to enter the consensus. Defaults to A value strictly between 0 and 1 is read as a proportion of
the methods that ran; anything else is a count, rounded up
( A count larger than the number of methods that ran cannot be reached, so the consensus would be empty by construction; that warns rather than returning a result indistinguishable from “the methods agreed on nothing”. |
change_in |
Passed to each detector. |
index |
Optional time index, carried onto the result. |
seed |
Optional seed for reproducibility. The seed is scoped to this
call: |
... |
Passed on to |
object |
A |
plot_type |
|
A ggcpt object (so it plots and tidies like any other
result) whose changepoints tibble carries votes and
methods (a comma-separated list of the methods that found each
location), with the per-method detections kept in a
consensus attribute and drawn by autoplot(plot_type =
"agreement").
Voting removes the idiosyncrasies of individual algorithms. It does not
remove a false positive that every algorithm makes for the same reason,
and a violated assumption is exactly such a reason: measured under
AR(1) noise, every one of pelt's spurious changepoints was
reproduced by wbs within five observations, and the 2-of-3
consensus of pelt, binseg and wbs had more false
positives (1.40) than two of its own members. The useful signal in a
panel is its disagreement: the disagreement value in
the consensus attribute is the share of the locations any member
found that not every member found, and a high value says the members'
shared assumption may be what is wrong (see
cpt_assumptions() and cpt_robustness()).
Agreement among detectors is not a p-value, and a location found
by six of seven methods is not thereby significant at any level: the
methods are run on the same data and are strongly correlated, several of
them share an engine, and none of the votes is independent. Read the vote
count as a robustness display ("this feature does not depend on which
detector I picked"), and use nsp_wrapper() or
cpt_confint() when you need a guarantee.
van den Burg GJJ, Williams CKI (2020). “An evaluation of change point detection algorithms.” arXiv preprint arXiv:2003.06222. doi:10.48550/arXiv.2003.06222.
ggcpt_compare(), cpt_recommend(),
cpt_metrics().
set.seed(2026) x <- c(rnorm(80), rnorm(80, 4)) cons <- cpt_consensus(x, methods = c("pelt", "binseg", "amoc")) tidy(cons) ggplot2::autoplot(cons)set.seed(2026) x <- c(rnorm(80), rnorm(80, 4)) cons <- cpt_consensus(x, methods = c("pelt", "binseg", "amoc")) tidy(cons) ggplot2::autoplot(cons)
Runs PELT once per distinct optimal segmentation as the penalty
ranges over [pen_min, pen_max], using the CROPS algorithm of
Haynes, Eckley and Fearnhead (2017) as implemented by the
changepoint package. Instead of committing to one penalty, the
analyst sees every segmentation the data admits along the path, together
with its cost, and picks the elbow.
cpt_crops( x, change_in = c("mean", "var", "meanvar"), pen_min = NULL, pen_max = NULL, ... ) ## S3 method for class 'ggcpt_path' autoplot( object, type = c("elbow", "path", "segmentations"), max_facets = 12, ... ) ## S3 method for class 'ggcpt_path' print(x, ...) ## S3 method for class 'ggcpt_path' tidy(x, ...)cpt_crops( x, change_in = c("mean", "var", "meanvar"), pen_min = NULL, pen_max = NULL, ... ) ## S3 method for class 'ggcpt_path' autoplot( object, type = c("elbow", "path", "segmentations"), max_facets = 12, ... ) ## S3 method for class 'ggcpt_path' print(x, ...) ## S3 method for class 'ggcpt_path' tidy(x, ...)
x |
For |
change_in |
What to detect change in: |
pen_min, pen_max
|
The penalty interval to sweep. Default to
|
... |
Additional arguments passed to the underlying
|
object |
A |
type |
Plot type for |
max_facets |
Maximum number of solutions shown by
|
A ggcpt_path object: a list with a solutions tibble
(one row per distinct segmentation: penalty, n_cpts,
cost, and a cpts list-column), the data, and
metadata. penalty is the lower end of the penalty
interval on which that segmentation is optimal: CROPS returns the
breakpoints of the penalty axis, so segmentations come with
boundaries and each row is optimal from its own
penalty up to the next row's. Methods: print(), tidy(), and
autoplot() (elbow plot by default;
type = "path" for penalty vs. number of changepoints;
type = "segmentations" for the faceted segmentations).
Haynes K, Eckley IA, Fearnhead P (2017). “Computationally efficient changepoint detection for a range of penalties.” Journal of Computational and Graphical Statistics, 26(1), 134–143.
Killick R, Eckley I (2014). “changepoint: An R package for changepoint analysis.” Journal of statistical software, 58(3), 1–19.
set.seed(2026) x <- c(rnorm(100), rnorm(100, 3), rnorm(100, -1)) path <- cpt_crops(x) path ggplot2::autoplot(path) ggplot2::autoplot(path, type = "segmentations")set.seed(2026) x <- c(rnorm(100), rnorm(100, 3), rnorm(100, -1)) path <- cpt_crops(x) path ggplot2::autoplot(path) ggplot2::autoplot(path, type = "segmentations")
Ten replicates of a 400-point series with one change at 200, at
comparable effect sizes across four data types: Gaussian (a shift of 1.4
standard deviations), Bernoulli (probability 0.15 to 0.75), Poisson (rate
2 to 10) and a proportion (binomial of 20, 0.25 to 0.6). Each engine is
at its default, as a user who does not set family gets it.
cpt_data_typescpt_data_types
A tibble with one row per engine and data type:
the engine.
"gaussian", "bernoulli",
"poisson" or "proportion".
replicates that ran.
share of replicates finding the change within 20 positions.
mean number of other reported changepoints.
data-raw/measure_engines.R (part datatype).
Other measurement tables:
cpt_calibration,
cpt_invariances,
cpt_noise_benchmark,
cpt_null_sizes,
cpt_runtimes
b <- subset(cpt_data_types, data_type == "bernoulli") b[order(-b$fp), ][1:5, ]b <- subset(cpt_data_types, data_type == "bernoulli") b[order(-b$fp), ][1:5, ]
Builds a ready-made collection of labelled series for
cpt_benchmark(). By default these are the canonical
simulated signals this package already ships, which means the benchmark
runs offline, deterministically, and inside R CMD check. Pass
source = "tcpd" for the Turing Change Point Dataset instead, which
is downloaded and cached.
cpt_datasets( source = c("simulated", "tcpd"), n = 500, seed = 1, names = NULL, ... )cpt_datasets( source = c("simulated", "tcpd"), n = 500, seed = 1, names = NULL, ... )
source |
|
n |
Length of each simulated series. Defaults to |
seed |
Seed for the simulated signals. Defaults to |
names |
Optional subset of dataset names. |
... |
Passed to |
A named list of list(series, annotations) datasets, ready
for cpt_benchmark().
cpt_load_tcpd(), cpt_benchmark().
names(cpt_datasets(n = 200))names(cpt_datasets(n = 200))
Scores an online result the way the sequential literature does: how long
after each true change did the first alarm arrive, and how many alarms
were raised with no change behind them. cpt_metrics() is the
wrong tool for an online detector: it asks whether the location
was recovered, which a sequential procedure never claims. It will not
stop you: cpt_metrics() takes bare integer vectors and never
sees which detector produced them, so it cannot know. (An earlier
version of this sentence said it warns. It does not, and given that
signature it could not.)
cpt_delay(object, truth, max_delay = Inf) ## S3 method for class 'ggcpt_delay' tidy(x, ...) ## S3 method for class 'ggcpt_delay' glance(x, ...) ## S3 method for class 'ggcpt_delay' print(x, ...) ## S3 method for class 'ggcpt_delay' autoplot(object, ...)cpt_delay(object, truth, max_delay = Inf) ## S3 method for class 'ggcpt_delay' tidy(x, ...) ## S3 method for class 'ggcpt_delay' glance(x, ...) ## S3 method for class 'ggcpt_delay' print(x, ...) ## S3 method for class 'ggcpt_delay' autoplot(object, ...)
object |
A |
truth |
Integer vector of true changepoint positions, on the same
clock as the alarms. When |
max_delay |
Alarms further than this after a change are treated as
false alarms rather than late detections. Defaults to |
x |
A |
... |
Ignored. |
A ggcpt_delay object: a list with per_change (one
row per true change: truth, alarm, delay,
detected), false_alarms, and the summary statistics
mean_delay, median_delay, n_false_alarms and
arl: monitored observations per false alarm. The baseline a
cpt_replay() monitor trained on is not counted, because
no alarm can fire there; n_obs is the length of the stream in
series positions, baseline included.
cpt_monitor(), cpt_replay().
set.seed(2026) mon <- cpt_replay(c(rnorm(200), rnorm(200, 3)), method = "edetector") cpt_delay(mon, truth = 200)set.seed(2026) mon <- cpt_replay(c(rnorm(200), rnorm(200, 3)), method = "edetector") cpt_delay(mon, truth = 200)
Runs a changepoint detection method on a sequence and returns a tidy
ggcpt result object. This is the recommended entry point for most
users. See cpt_methods() for the full method table with
engines and capabilities.
cpt_detect( x, method = "pelt", change_in = "mean", penalty = "MBIC", index = NULL, y = NULL, ..., data = NULL, family = NULL, group = NULL, na_action = c("error", "omit", "engine"), fixed = NULL, within = NULL, min_segment = NULL, min_effect = NULL, keep_fit = TRUE )cpt_detect( x, method = "pelt", change_in = "mean", penalty = "MBIC", index = NULL, y = NULL, ..., data = NULL, family = NULL, group = NULL, na_action = c("error", "omit", "engine"), fixed = NULL, within = NULL, min_segment = NULL, min_effect = NULL, keep_fit = TRUE )
x |
The series. A numeric vector for univariate methods, or a
numeric matrix/data frame (rows are time points) for the multivariate
methods (run Also a formula with Several series at once: a dplyr-grouped data frame, a keyed
Refused rather than coerced: a factor (its level codes are not data),
a survival object, and dates or timestamps as values (they convert to
an increasing count; pass them as |
method |
Detection method: any |
change_in |
What to detect change in. One of A compatible request may still be routed to the method's own
native change type, because several engines have no separate estimator
for the thing being asked about. That is never silent: the result's
|
penalty |
Penalty type or value. Either a character string
( |
index |
Optional time index, one value per observation (dates, say).
Detection still runs on observation positions (every wrapped engine
assumes an equally spaced sequence), but the index is stored on the
result and threaded through |
y |
Column selection for the data-frame interface:
|
... |
Additional arguments passed to the specific wrapper (see the
wrapper's help page for engine-specific options). Where an argument is
also derived from |
data |
A data frame for the formula interface. |
family |
The distribution a segment is modelled with:
|
group |
For a long data frame holding several series, the column(s)
identifying each one: a bare name, a string, or |
na_action |
What to do with missing values: |
fixed |
Changepoints known in advance, which are kept and the rest
estimated around them: the detector runs separately on each stretch
between them. Positions, or values of the series' index (a date is
placed at the last observation on or before it; for a numeric index
such as a |
within |
Windows the changepoints must fall in ("the policy took
effect sometime in Q2"): a pair |
min_segment |
Minimum segment length in observations, translated
into each engine's own argument ( |
min_effect |
Drop changepoints whose mean shift is smaller than this
many noise standard deviations (estimated from the series' first
differences, which a changepoint barely moves), removing the smallest
first and re-measuring its neighbours after each removal. For a change
in mean only. The size is measured on the same data that located the
change, so it is biased upward; see |
keep_fit |
Keep the engine's own object in |
A ggcpt object: a list with changepoints
(cp, cp_value), segments (seg_id,
start, end, n, param_estimate),
data (index, value), the method,
change_in, penalty, cp_convention and
runtime that produced it, the matched call, and
fit, the raw upstream object. Optional slots
(data_wide, regions, diagnostics, ...) appear
only when an engine supplies them; new_ggcpt()
documents all of them, and tidy.ggcpt(),
glance.ggcpt() and augment.ggcpt()
are the supported way to read one.
"pelt", "binseg", "segneigh" and "fpop"
compare a penalty against a raw segment cost when
change_in = "mean": changepoint's Normal cost assumes a
noise standard deviation of 1, and fpop's lambda is an
absolute penalty on the residual sum of squares. Neither rescales the
data, so on a series whose noise is much wider than 1 the penalty is
effectively negligible and the segmentation shatters. On 200 observations
with one true changepoint in the middle and a jump of five standard
deviations, "pelt" returns 1 changepoint at , 27
at and 76 at . These are means over 20
draws, because a single draw is not stable here: the same settings gave
15/38 at and 47/152 at , so the effect grows
with the series as well as with the noise. (0.5.0, before the two-point
minimum segment, reported 39 and 141 at : the floor halves
the damage and does not remove it.) A measured scale-sensitive engine
given noise far from unit scale warns (class
ggchangepoint_scale_sensitive). Three ways to avoid it, in order
of convenience:
standardise the series first
(cpt_detect(scale(x)[, 1], method = "pelt"));
pass a penalty on the data's own scale, for example
penalty = 2 * log(length(x)) * stats::var(diff(x)) / 2;
use change_in = "meanvar", which estimates a variance per
segment and is unaffected.
Most other engines are unaffected: SMUCE, WBS, WBS2, NOT, MOSUM,
Isolate-Detect, TGUH, CPOP, "bcp", "beast" and the
nonparametric and multivariate methods estimate or cancel the noise scale
internally, and returned the same segmentation at a thousandth, one and
a thousand times the units. Five did not, on the same series:
"geomcp" runs PELT on its mapped distance and angle series and so
inherits the sensitivity above; "decafs" floors its noise
estimate at about 0.03, so it under-segments a series whose noise is
smaller than that; "bocpd"'s default prior is on the data's
own scale; and "envcpt" and "var" changed their answer
with the units too (var's gamma_set and lambda_set
penalise a squared-error loss on an absolute scale). At a
thousandth of the units "decafs", "bocpd" and
"var" found nothing. Standardising first avoids all five, and
cpt_invariances holds the measurement.
cpt_methods() for what is available and what each
method can do. To get the result out: tidy.ggcpt(),
glance.ggcpt(), augment.ggcpt(),
summary.ggcpt() and print.ggcpt(). To
draw it: autoplot.ggcpt(). For the penalty:
cpt_penalty().
set.seed(2022) x <- c(rnorm(100, 0, 1), rnorm(100, 10, 1)) result <- cpt_detect(x, method = "pelt", change_in = "mean") result ggplot2::autoplot(result) # A date index: detection is unchanged, but the report speaks in dates. dates <- as.Date("2000-01-01") + 0:199 dated <- cpt_detect(x, method = "pelt", index = dates) tidy(dated) # The data-frame interface. df <- data.frame(day = dates, value = x) cpt_detect(df, y = value, index = day, method = "pelt") # Counts, with a cost written for them. counts <- c(rpois(100, 2), rpois(100, 6)) cpt_detect(counts, method = "pelt", family = "poisson") # Missing values, located in the original positions. gappy <- x gappy[c(20, 21, 150)] <- NA cpt_detect(gappy, method = "pelt", na_action = "omit")$changepoints # A changepoint known in advance, and a window for another. cpt_detect(x, method = "pelt", fixed = 50)$changepoints # Breakpoints in a regression. if (requireNamespace("strucchange", quietly = TRUE)) { d <- data.frame(t = 1:200, z = rnorm(200)) d$y <- ifelse(d$t <= 120, 1 + d$z, 3 - d$z) + rnorm(200, 0, 0.5) fit <- cpt_detect(y ~ z, data = d, method = "strucchange") tidy(fit, "coefficients") }set.seed(2022) x <- c(rnorm(100, 0, 1), rnorm(100, 10, 1)) result <- cpt_detect(x, method = "pelt", change_in = "mean") result ggplot2::autoplot(result) # A date index: detection is unchanged, but the report speaks in dates. dates <- as.Date("2000-01-01") + 0:199 dated <- cpt_detect(x, method = "pelt", index = dates) tidy(dated) # The data-frame interface. df <- data.frame(day = dates, value = x) cpt_detect(df, y = value, index = day, method = "pelt") # Counts, with a cost written for them. counts <- c(rpois(100, 2), rpois(100, 6)) cpt_detect(counts, method = "pelt", family = "poisson") # Missing values, located in the original positions. gappy <- x gappy[c(20, 21, 150)] <- NA cpt_detect(gappy, method = "pelt", na_action = "omit")$changepoints # A changepoint known in advance, and a window for another. cpt_detect(x, method = "pelt", fixed = 50)$changepoints # Breakpoints in a regression. if (requireNamespace("strucchange", quietly = TRUE)) { d <- data.frame(t = 1:200, z = rnorm(200)) d$y <- ifelse(d$t <= 120, 1 + d$z, 3 - d$z) + rnorm(200, 0, 0.5) fit <- cpt_detect(y ~ z, data = d, method = "strucchange") tidy(fit, "coefficients") }
The size of every change a fit reports, in the data's own units and standardised: the level before and after, their difference with an interval, the difference in noise standard deviations, the percentage change, and for count and waiting-time data the rate or hazard ratio.
cpt_effect(fit, level = 0.95, method = c("naive", "split"), seed = NULL, ...) ## S3 method for class 'ggcpt_effect' print(x, ...) ## S3 method for class 'ggcpt_effect' tidy(x, ...) ## S3 method for class 'ggcpt_effect' autoplot(object, ...)cpt_effect(fit, level = 0.95, method = c("naive", "split"), seed = NULL, ...) ## S3 method for class 'ggcpt_effect' print(x, ...) ## S3 method for class 'ggcpt_effect' tidy(x, ...) ## S3 method for class 'ggcpt_effect' autoplot(object, ...)
fit |
A |
level |
Confidence level for the intervals. Defaults to |
method |
|
seed |
Optional seed for |
... |
Further arguments for the re-run |
x |
A |
object |
A |
A ggcpt_effect tibble with one row per changepoint (per
changepoint and coordinate for a multivariate fit, per changepoint and
term for a regression fit): cp (and cp_index),
before, after, n_before, n_after,
delta, delta_lower, delta_upper (a Welch
interval), delta_std (the change in noise standard deviations,
the unit cpt_detect(min_effect = ) filters on),
pct_change, sd_before, sd_after,
sd_ratio, the family-specific ratio where it applies
(rate_ratio for Poisson counts, odds_ratio for binary
data, hazard_ratio for exponential waiting times, each with an
interval), selection_adjusted and method. With
print() and autoplot().
A change measured at a location the same data chose is biased upward:
the detector put the boundary where the two sides differ most, so the
difference it reports is the largest the noise allowed. The bias is
worst for the marginal detections, which are exactly the ones whose size
matters. method = "naive" rows carry selection_adjusted =
FALSE for that reason, except at a changepoint fixed in advance with
cpt_detect(fixed = ), which the data did not locate and which is
TRUE. method = "split" is honest about the size
(the measuring half never influenced the locations) and less precise
about the location (the locating half has half the data), and it assumes
the noise is independent from one observation to the next, since the
two halves are interleaved.
cpt_test_at() for a change at a date fixed in
advance, cpt_detect()'s min_effect.
Other inference:
cpt_assumptions(),
cpt_attribute_event(),
cpt_gof(),
cpt_null_power(),
cpt_robustness(),
cpt_test_at(),
cpt_test_null()
set.seed(1) fit <- cpt_detect(c(rnorm(100, 10), rnorm(100, 12)), method = "pelt") cpt_effect(fit) counts <- c(rpois(100, 4), rpois(100, 8)) cpt_effect(cpt_detect(counts, method = "pelt", family = "poisson"))set.seed(1) fit <- cpt_detect(c(rnorm(100, 10), rnorm(100, 12)), method = "pelt") cpt_effect(fit) counts <- c(rpois(100, 4), rpois(100, 8)) cpt_effect(cpt_detect(counts, method = "pelt", family = "poisson"))
cpt_export() writes a result where software in any language can
read it; cpt_import() rebuilds a working ggcpt from the
file. A saved .rds already reads in any R session without this
package (a ggcpt is a plain list of plain data), so these are for
leaving R, or for a format a person can open.
cpt_export(fit, file, format = NULL, ...) cpt_import(file, format = NULL, method = "imported", change_in = "mean")cpt_export(fit, file, format = NULL, ...) cpt_import(file, format = NULL, method = "imported", change_in = "mean")
fit |
A |
file |
Path to write ( |
format |
|
... |
For |
method, change_in
|
For a CSV, which carries no metadata, the method
and change type to record on the rebuilt result. Defaults to
|
cpt_export() returns file, invisibly.
cpt_import() returns a ggcpt object; the engine's own
$fit is not stored in either format, so it is NULL.
Other result class:
annotate_segments(),
as_cpt_series(),
as_ggcpt(),
as_json(),
cpt_annotations(),
cpt_verify(),
ggchangepoint-conditions,
is_ggcpt(),
new_ggcpt(),
print.ggcpt()
set.seed(1) fit <- cpt_detect(c(rnorm(50), rnorm(50, 3)), method = "pelt") path <- tempfile(fileext = ".json") cpt_export(fit, path) back <- cpt_import(path) back$changepoints unlink(path)set.seed(1) fit <- cpt_detect(c(rnorm(50), rnorm(50, 3)), method = "pelt") path <- tempfile(fileext = ".json") cpt_export(fit, path) back <- cpt_import(path) back$changepoints unlink(path)
The family argument of cpt_detect() names the
distribution a segment is modelled with, so count data, waiting times
and binary series can be segmented with a cost written for them rather
than a Gaussian one. cpt_families() is the table behind it: every
legal combination of method, change_in and family,
and the engine call each becomes.
cpt_families(method = NULL)cpt_families(method = NULL)
method |
Optional method name(s) to restrict the table to. |
A tibble with one row per legal combination: method,
change_in, family (NA for a distribution-free
method, which takes no family), engine_call (what is run) and
data (what the family requires of the series: "counts",
"binary", "positive" or NA).
"gaussian"The default of every parametric method. On
"cpm" it also switches from the nonparametric statistics to
the Gaussian ones (Student, Bartlett).
"poisson"Counts: change_in = "mean" is a change
in the rate. Needs non-negative whole numbers.
"binomial"Binary outcomes: a change in the success probability. Needs 0/1 data.
"exponential"Waiting times: a change in the rate (the
hazard), so change_in = "mean". Needs positive data.
"gamma"Positive data with a known shape (pass
shape, default 1): a change in the scale.
"laplace"Heavy tails: a change in the median and the
scale (change_in = "meanvar").
"l1"The absolute-loss cost: a change in the median,
robust to outliers (change_in = "mean").
A single-parameter family has one thing to change, so Poisson,
binomial, exponential and gamma requests use change_in = "mean".
A grammar that marks the changing parameter
(poisson(rate = NA), normal(mean = NA, sd = 1)) would unify
change_in, family and the formula interface in one
expression, and measured against the fifty methods it fits 42 of them
cleanly. It is deferred to 1.0, where change_in can be replaced
rather than joined by a second idiom, and this table is the first half of
it: change_in = "mean", family = "poisson" already means
poisson(rate = NA) internally.
cpt_detect(), cpt_methods() (its
families column), cpt_simulate() to generate
data from each family.
cpt_families("pelt") # every method that can fit a Poisson rate unique(subset(cpt_families(), family == "poisson")$method) set.seed(1) counts <- c(rpois(100, 3), rpois(100, 9)) cpt_detect(counts, method = "pelt", family = "poisson")cpt_families("pelt") # every method that can fit a Poisson rate unique(subset(cpt_families(), family == "poisson")$method) set.seed(1) counts <- c(rpois(100, 3), rpois(100, 9)) cpt_detect(counts, method = "pelt", family = "poisson")
The checks behind a segmentation, as numbers: for every segment, its length, level and spread, whether its residuals look independent (Ljung-Box) and Gaussian (Shapiro-Wilk), and a flag where the segment is too short for either test to mean anything.
cpt_gof(fit, lag = NULL) ## S3 method for class 'ggcpt_gof' print(x, ...) ## S3 method for class 'ggcpt_gof' tidy(x, ...)cpt_gof(fit, lag = NULL) ## S3 method for class 'ggcpt_gof' print(x, ...) ## S3 method for class 'ggcpt_gof' tidy(x, ...)
fit |
A |
lag |
Ljung-Box lag. Defaults to |
x |
A |
... |
Ignored. |
A ggcpt_gof tibble with one row per segment (per segment
and coordinate for a multivariate fit): seg_id, start,
end, n, mean, sd, acf1 (lag-1
autocorrelation of the residuals), ljung_box_p,
shapiro_p, and too_short (fewer than 12 observations,
where the tests are left NA). The whole-series Ljung-Box result
is attached as the "overall" attribute, and print()
summarises what the columns say.
autoplot(fit, type = "diagnostics") draws the same
checks; cpt_assumptions() reports them with the
alternatives.
Other inference:
cpt_assumptions(),
cpt_attribute_event(),
cpt_effect(),
cpt_null_power(),
cpt_robustness(),
cpt_test_at(),
cpt_test_null()
set.seed(1) fit <- cpt_detect(c(rnorm(100), rnorm(100, 3, 2)), method = "pelt") cpt_gof(fit)set.seed(1) fit <- cpt_detect(c(rnorm(100), rnorm(100, 3, 2)), method = "pelt") cpt_gof(fit)
Renders the changepoints of a result as a gt table, with the time index, location intervals and segment levels formatted for a paper. Falls back to a plain tibble, with a note, when gt is not installed.
cpt_gt(object, title = NULL, subtitle = NULL, digits = 3)cpt_gt(object, title = NULL, subtitle = NULL, digits = 3)
object |
A |
title, subtitle
|
Table title and subtitle. Sensible defaults are derived from the result. |
digits |
Digits for the numeric columns. Defaults to |
A gt table, or a tibble when gt is unavailable.
cpt_report().
set.seed(2026) cpt_gt(cpt_detect(c(rnorm(60), rnorm(60, 4)), method = "pelt"))set.seed(2026) cpt_gt(cpt_detect(c(rnorm(60), rnorm(60, 4)), method = "pelt"))
Perturbs one observation at a time (deleting it, or replacing it with an outlier), re-runs the detector, and reports what changed: the number of changepoints, where they moved to, and how the segment parameters responded. This is the diagnostic family of Wilms, Killick and Matteson (2022), rendered in ggplot2 so it composes with the rest of the package.
cpt_influence( object, type = c("delete", "outlier"), engine = c("auto", "changepoint.influence", "recompute"), subset = NULL, outlier_sd = 5, seed = NULL, ... ) ## S3 method for class 'ggcpt_influence' print(x, ...) ## S3 method for class 'ggcpt_influence' autoplot( object, plot_type = c("overview", "location", "parameter", "map"), ... ) ## S3 method for class 'ggcpt_influence' tidy(x, ...)cpt_influence( object, type = c("delete", "outlier"), engine = c("auto", "changepoint.influence", "recompute"), subset = NULL, outlier_sd = 5, seed = NULL, ... ) ## S3 method for class 'ggcpt_influence' print(x, ...) ## S3 method for class 'ggcpt_influence' autoplot( object, plot_type = c("overview", "location", "parameter", "map"), ... ) ## S3 method for class 'ggcpt_influence' tidy(x, ...)
object |
A |
type |
|
engine |
Which implementation to use:
|
subset |
Optional integer vector of observation positions to perturb. Influence by deletion costs one detector fit per observation, so on a long series or an expensive engine this is the argument that makes the diagnostic affordable. Defaults to every observation. |
outlier_sd |
For |
seed |
Optional seed, for detectors that randomise. The seed is
scoped to this call: |
... |
Additional arguments passed to |
x |
A |
plot_type |
Which diagnostic to draw:
|
A ggcpt_influence object: a list with
influencea tibble with one row per perturbed
observation: index, n_cp, delta_n_cp (against
the unperturbed fit), max_shift (largest movement of a
surviving changepoint, in positions), param_shift (largest
absolute change in a segment parameter) and cpts (a
list-column of the perturbed changepoint sets). A perturbation
whose re-fit failed has n_cp = NA, and is warned about;
paraman matrix of per-observation
segment parameters, one row per perturbation: the input to the
influence map;
original, type, engine, method
with print() and autoplot() methods.
Wilms I, Killick R, Matteson DS (2022). “Graphical influence diagnostics for changepoint models.” Journal of Computational and Graphical Statistics, 31(3), 753–765. doi:10.1080/10618600.2021.2000873.
cpt_leverage(), cpt_sensitivity(),
cpt_stability().
set.seed(2026) fit <- cpt_detect(c(rnorm(40), rnorm(40, 4)), method = "pelt") inf <- cpt_influence(fit) inf head(cpt_leverage(inf))set.seed(2026) fit <- cpt_detect(c(rnorm(40), rnorm(40, 4)), method = "pelt") inf <- cpt_influence(fit) inf head(cpt_leverage(inf))
The package wraps a lot of upstream engines, all of them in
Suggests so that installing ggchangepoint does not drag in
dozens of packages nobody asked for. The cost of that choice is a
discovery problem: cpt_detect(x, method = "smuce") tells you to
install stepR, but only one package at a time. This installs a whole
family in one call.
cpt_install_engines(bundle = "core", dry_run = FALSE, ...)cpt_install_engines(bundle = "core", dry_run = FALSE, ...)
bundle |
Which family to install:
Several bundles may be given at once. |
dry_run |
Report what would be installed without installing
anything. Defaults to |
... |
Passed to |
Every package comes from the repositories in getOption("repos")
except the two engines CRAN has archived. fpop, archived in
September 2026 at its maintainer's request, is installed from R-Forge
(https://R-Forge.R-project.org), where it is developed. ocp,
archived in October 2026, is installed from the package website
(https://pursuitofdatascience.github.io/ggchangepoint/repo/), a
CRAN-like repository that serves the last CRAN release of every engine
CRAN no longer does.
Invisibly, a tibble with one row per package (package,
bundle, installed_before, installed_after).
cpt_methods() for the per-method installation
status.
cpt_install_engines("bayesian", dry_run = TRUE)cpt_install_engines("bayesian", dry_run = TRUE)
Five replicates of a 200-point series with changes at 70 and 140 (a
3-coordinate version for the multivariate engines), detected as given and
transformed. A correct mean-change detector returns the same
changepoints on 10 * x, 0.1 * x and x + 100, and
n - cp on the reversed series.
cpt_invariancescpt_invariances
A tibble with one row per engine:
the method.
replicates that ran.
median changepoints on the series as given.
the same answer at x, 10 * x and
0.1 * x in at least four of five replicates. FALSE for
the Gaussian-cost engines that assume unit noise, which is why
cpt_detect() warns when one is handed noise far from unit
scale.
the same answer on x + 100.
share of replicates whose reversed series gives the mirrored answer.
the reversal test fails in most replicates: the answer depends on the direction of time.
median changepoints on c(x, x) (four expected,
one for a single-change design).
median changepoints when every observation is repeated twice, which makes the noise strongly autocorrelated: a measure of how badly the engine fails when its independence assumption does.
data-raw/measure_engines.R (part invariance).
Other measurement tables:
cpt_calibration,
cpt_data_types,
cpt_noise_benchmark,
cpt_null_sizes,
cpt_runtimes
subset(cpt_invariances, !scale_invariant)$methodsubset(cpt_invariances, !scale_invariant)$method
Counts label errors: a positive region with no changepoint is a false
negative, a negative region with one is a false positive, and a
"one_change" region with two or more is a false positive as well.
This is the accuracy measure supervised changepoint detection is built on,
and, unlike an information criterion, it is defined by what the expert
asserted rather than by a model assumption.
cpt_label_error(object, labels) ## S3 method for class 'cpt_label_error' tidy(x, ...) ## S3 method for class 'cpt_label_error' print(x, ...)cpt_label_error(object, labels) ## S3 method for class 'cpt_label_error' tidy(x, ...) ## S3 method for class 'cpt_label_error' print(x, ...)
object |
A |
labels |
A |
x |
A |
... |
Ignored. |
A tibble with one row per label: label_id,
series (the label set's series identifier, NA for a
single unnamed series), start, end, change,
n_changes (how many detections fell inside), status ("correct", "false_positive" or
"false_negative"), carrying the totals in an errors
attribute and printing them. An empty label set gives a zero-row
tibble with the same columns.
cpt_labels(),
cpt_label_error_curve(), geom_cpt_label().
set.seed(2026) fit <- cpt_detect(c(rnorm(50), rnorm(50, 4)), method = "pelt") labs <- cpt_labels(c(40, 70), c(60, 95), c("one_change", "no_change")) cpt_label_error(fit, labs)set.seed(2026) fit <- cpt_detect(c(rnorm(50), rnorm(50, 4)), method = "pelt") labs <- cpt_labels(c(40, 70), c(60, 95), c("one_change", "no_change")) cpt_label_error(fit, labs)
Runs one detector across a penalty grid and counts label errors at each setting: the curve penalty learning is fitted to, and the honest way to see whether any penalty can satisfy the labels.
cpt_label_error_curve( x, labels, method = "pelt", penalties = NULL, change_in = "mean", ... ) ## S3 method for class 'ggcpt_label_curve' print(x, ...) ## S3 method for class 'ggcpt_label_curve' tidy(x, ...) ## S3 method for class 'ggcpt_label_curve' autoplot(object, ...)cpt_label_error_curve( x, labels, method = "pelt", penalties = NULL, change_in = "mean", ... ) ## S3 method for class 'ggcpt_label_curve' print(x, ...) ## S3 method for class 'ggcpt_label_curve' tidy(x, ...) ## S3 method for class 'ggcpt_label_curve' autoplot(object, ...)
x |
A |
labels |
A |
method |
Detection method. Defaults to |
penalties |
Numeric vector of penalties to try. When |
change_in |
Passed to the detector. |
... |
Additional arguments passed to |
object |
A |
A ggcpt_label_curve object: a tibble with penalty,
n_cp, errors, false_positive,
false_negative, plus print(), tidy() and
autoplot().
The target attribute holds the interval of log(penalty)
achieving the minimum error, which is what
cpt_learn_penalty() regresses on.
cpt_learn_penalty(), cpt_select().
set.seed(2026) x <- c(rnorm(60), rnorm(60, 4)) labs <- as_cpt_labels(60, n = 120) curve <- cpt_label_error_curve(x, labs, penalties = c(2, 8, 32, 128)) curveset.seed(2026) x <- c(rnorm(60), rnorm(60, 4)) labs <- as_cpt_labels(60, n = 120) curve <- cpt_label_error_curve(x, labs, penalties = c(2, 8, 32, 128)) curve
Builds the tidy label set that the supervised functions consume: one row per labelled region, each asserting how many changepoints that stretch of the series contains.
cpt_labels(start, end, change = "change", series = NA_character_) ## S3 method for class 'cpt_labels' tidy(x, ...)cpt_labels(start, end, change = "change", series = NA_character_) ## S3 method for class 'cpt_labels' tidy(x, ...)
start, end
|
Integer vectors of region boundaries (positions, inclusive). |
change |
What the region asserts, recycled to length:
|
series |
Optional series identifier, for label sets spanning a panel. |
x |
A |
... |
Ignored. |
A cpt_labels tibble with columns label_id,
series, start, end, change.
Hocking TD, Rigaill G, Vert J, Bach F (2013). “Learning sparse penalties for change-point detection using max margin interval regression.” In Proceedings of the 30th International Conference on Machine Learning, volume 28, 172–180.
cpt_label_error(), geom_cpt_label(),
cpt_learn_penalty(),
as_cpt_labels() to convert a plain changepoint set.
cpt_labels(c(40, 70), c(60, 90), c("change", "no_change"))cpt_labels(c(40, 70), c(60, 90), c("change", "no_change"))
Fits the supervised penalty model of Hocking et al. (2013): each series
contributes a target interval of log-penalties (those achieving the
fewest label errors), a feature vector is computed from the series, and a
linear model is fitted by minimising the squared hinge loss on those
intervals, which is max-margin interval regression. The result has a
predict() method, and cpt_detect() accepts it
directly as penalty, so a learned penalty is used exactly like a
number.
cpt_learn_penalty( series, labels, method = "pelt", penalties = NULL, engine = c("auto", "penaltyLearning", "native"), ... ) ## S3 method for class 'ggcpt_penalty_model' print(x, ...) ## S3 method for class 'ggcpt_penalty_model' coef(object, ...) ## S3 method for class 'ggcpt_penalty_model' tidy(x, ...) ## S3 method for class 'ggcpt_penalty_model' predict(object, newdata, ...)cpt_learn_penalty( series, labels, method = "pelt", penalties = NULL, engine = c("auto", "penaltyLearning", "native"), ... ) ## S3 method for class 'ggcpt_penalty_model' print(x, ...) ## S3 method for class 'ggcpt_penalty_model' coef(object, ...) ## S3 method for class 'ggcpt_penalty_model' tidy(x, ...) ## S3 method for class 'ggcpt_penalty_model' predict(object, newdata, ...)
series |
A named list of numeric vectors (or a matrix/data frame with one column per series). |
labels |
Either a single |
method |
Detection method used to build the label-error curves.
Defaults to |
penalties |
Penalty grid for the curves; passed to
|
engine |
|
... |
Additional arguments passed to |
x |
A |
object |
A |
newdata |
A numeric vector (one series), or a list/matrix of series. |
A ggcpt_penalty_model object with print(),
coef(), tidy() (the coefficients as term and
estimate) and predict() methods.
The two scales differ and it matters: coef() gives an
intercept plus one weight per feature on the log-penalty
scale, which is where the interval regression is fitted, while
predict() exponentiates and returns a penalty on the natural
scale, the scale cpt_penalty() and
cpt_detect() consume. So a coefficient of
on log_n is a multiplicative effect on the
penalty, not an additive one.
The signs are often not interpretable, and that is a property of
the labels rather than of the fit. A target interval is open above
whenever the largest penalty on the grid still achieves the minimum
label error, which is the common case, because a large penalty
usually keeps the one changepoint the labels ask for. When every
series' interval is open above, any sufficiently large prediction is
optimal, the problem does not pin the slopes, and the term
settles them near zero with whatever sign the optimiser reached.
Two measurements on four series of very different length and noise,
all with one-change labels, differing only in the data drawn. In one,
every non-intercept coefficient came out slightly negative, so the
predicted penalty decreased with , the opposite of the
growth a reader would expect from BIC, and not evidence
of anything. In the other, every feature weight went to zero and the
model became a constant: predict() returned the same
penalty for all four series. Both fits put every prediction inside its
target, which is the property the model is fitted for, and neither
outcome says anything about how a penalty should scale.
So do not read a ggcpt_penalty_model as having discovered a
relationship, and do not be surprised by a constant one.
If the coefficients need to mean something, the labels have to
constrain the penalty from both sides: widen penalties until
the largest one starts to over-segment, so the target intervals close
above. cpt_label_error_curve() shows whether they do.
Hocking TD, Rigaill G, Vert J, Bach F (2013). “Learning sparse penalties for change-point detection using max margin interval regression.” In Proceedings of the 30th International Conference on Machine Learning, volume 28, 172–180.
cpt_label_error_curve(),
cpt_penalty().
set.seed(2026) series <- list(a = c(rnorm(60), rnorm(60, 4)), b = c(rnorm(80), rnorm(80, 2))) labels <- list(a = as_cpt_labels(60, n = 120), b = as_cpt_labels(80, n = 160)) model <- cpt_learn_penalty(series, labels, penalties = c(2, 8, 32, 128)) model stats::predict(model, series$a)set.seed(2026) series <- list(a = c(rnorm(60), rnorm(60, 4)), b = c(rnorm(80), rnorm(80, 2))) labels <- list(a = as_cpt_labels(60, n = 120), b = as_cpt_labels(80, n = 160)) model <- cpt_learn_penalty(series, labels, penalties = c(2, 8, 32, 128)) model stats::predict(model, series$a)
Orders the observations of a cpt_influence() result by how
much perturbing them disturbs the segmentation, most influential first.
The composite leverage score is the sum of three standardised
components (the change in the number of changepoints, the largest
movement of a changepoint, and the largest change in a segment
parameter), so an observation that shifts a location without changing the count is
still ranked.
cpt_leverage(object, ...)cpt_leverage(object, ...)
object |
A |
... |
Passed to |
A tibble ordered most influential first, with columns
index, delta_n_cp, max_shift,
param_shift and leverage.
Rows with leverage = NA come first, and they are the
most influential of all. max_shift and param_shift
are undefined for a perturbation that left the engine with no
changepoints at all (there is nothing to match against and no
parameters to compare), so the composite score cannot be formed for
an observation whose removal destroys the segmentation entirely. The
NA is kept rather than filled in with a fabricated number;
read the delta_n_cp column on those rows, which says how many
changepoints were lost.
An NA here is always that case. If the original fit
found no changepoints then max_shift is missing for every
observation, the standardisation returns zeros rather than
NAs, and every leverage is finite. A perturbation whose
re-fit failed is not one of these: it carries
delta_n_cp = NA as well and is sorted last, since nothing is
known about it.
set.seed(2026) fit <- cpt_detect(c(rnorm(40), rnorm(40, 4)), method = "pelt") head(cpt_leverage(fit), 3)set.seed(2026) fit <- cpt_detect(c(rnorm(40), rnorm(40, 4)), method = "pelt") head(cpt_leverage(fit), 3)
Fetches the benchmark of van den Burg and Williams (2020), real series
from many domains each annotated independently by several human
annotators, and caches it under tools::R_user_dir(). The
multi-annotator structure is the point: scoring against a single "true"
set silently discards the disagreement, and
cpt_metrics_annotated() is built to keep it.
cpt_load_tcpd(name = NULL, cache_dir = NULL, refresh = FALSE, quiet = FALSE)cpt_load_tcpd(name = NULL, cache_dir = NULL, refresh = FALSE, quiet = FALSE)
name |
Dataset name, a character vector of names, or |
cache_dir |
Where to cache. Defaults to
|
refresh |
Re-download even when a cached copy exists? Defaults to
|
quiet |
Suppress progress messages. Defaults to |
With name = NULL, a tibble catalogue (name,
n_annotators, cached), read from the annotations file
alone, so listing it downloads no series.
Otherwise a named list of list(series, annotations, index,
longname) datasets, in the shape cpt_benchmark() takes.
This function downloads from GitHub, so it needs a working connection and is skipped in every example and test here. The data belong to their original owners under their own licences; this package neither bundles nor redistributes them. A few TCPD series are not in the repository at all (their sources do not permit redistribution) and are reported as unavailable rather than silently omitted.
van den Burg GJJ, Williams CKI (2020). “An evaluation of change point detection algorithms.” arXiv preprint arXiv:2003.06222. doi:10.48550/arXiv.2003.06222.
# Not run by R CMD check: every call downloads from the Turing Change # Point Dataset's GitHub repository, and an example must not require # network access. ## Not run: cpt_load_tcpd() # the catalogue d <- cpt_load_tcpd("nile") # one dataset cpt_benchmark(d, methods = c("pelt", "amoc")) ## End(Not run)# Not run by R CMD check: every call downloads from the Turing Change # Point Dataset's GitHub repository, and an example must not require # network access. ## Not run: cpt_load_tcpd() # the catalogue d <- cpt_load_tcpd("nile") # one dataset cpt_benchmark(d, methods = c("pelt", "amoc")) ## End(Not run)
Returns a tibble describing every method the package knows about (those
that are wired, those a user has registered with
cpt_register_method(), and those that are planned), along
with their capabilities and installation status. Useful for discovering
what can be run, what needs to be installed, and which methods expose the
extras the diagnostics need (confidence intervals, a fitted signal, a
posterior, a detector statistic, a solution path, a bandwidth to sweep).
cpt_methods(capabilities = TRUE)cpt_methods(capabilities = TRUE)
capabilities |
Include the capability flag columns? Defaults to
|
A tibble with columns:
Method name as passed to cpt_detect().
What types of change the method can detect.
The upstream R package that implements the method.
"available" (wired in this release),
"registered" (supplied by the user this session; see
cpt_register_method()), or "planned"
(future).
TRUE if the engine package is installed,
FALSE if it is a Suggests engine that is missing,
NA for planned and registered methods.
What a planned method is waiting on: a release,
or "when on CRAN" when the engine package itself is not
available from CRAN. NA for methods that are already
wired. Asking cpt_detect() for a planned method reports
this rather than claiming the name does not exist.
Capability flags (omitted when
capabilities = FALSE). ci means the engine
supplies changepoint-location confidence intervals; fitted
a length- fitted signal; posterior a per-location
posterior probability; statistic and path the
internals rendered by ggcpt_statistic() and
ggcpt_solution_path(), which error with the list
of supporting engines when a result does not carry them.
scale_space is not one of those, despite sitting beside
them. Nothing stores a scale space on a result:
cpt_scale_space() computes one on demand by
sweeping a multiscale detector's bandwidth over the series, so
it works on any series and any result, a pelt
fit included. What this column marks is the two engines that
sweep can be run with, i.e. the domain of that
function's own method argument:
subset(cpt_methods(), scale_space)$method.
online means the algorithm is sequential (it
consumes observations one at a time), and this table reports it
because it governs how the method behaves in batch: an online
detector's threshold is a rate per observation, so run over a
whole series through cpt_detect() it reports
roughly changepoints by construction.
It does not mean the method can be passed to
cpt_monitor(), which takes its own three:
"edetector", "cpm" and "ocd". The two
sets overlap without coinciding: bocpd is an online
algorithm this table marks but the monitor does not offer, and
edetector is native to this package rather than a
wrapped engine, so it has no row here at all.
The modelling vocabulary (omitted when
capabilities = FALSE): the distribution families
cpt_detect(family = ) accepts (see
cpt_families(); NA for a distribution-free
method); the engine's modelling-choice arguments and their legal
values, which cpt_detect() validates; whether it takes a
formula with covariates; the engine argument
min_segment is translated into; what the engine does with
a missing value, measured rather than read from its
documentation ("native", "compacts",
"silent_loss" or "reject"; see
cpt_detect(na_action = )); and the engine's own
changepoint convention, which the wrapper translates to
"left" ("right": it reports the first observation
after the change; "continuous": a location it estimates
on a continuous scale; "design": rows of a lagged design).
Measured and recorded properties (omitted
when capabilities = FALSE): whether the answer is the same
at x, 10 * x and 0.1 * x; whether it
depends on the direction of time; how many changepoints the
method can return where that is fixed; "general" for the
general-purpose workhorses; the argument that selects the noise
model and the one that sets the false-alarm rate; the runtime
class at ("fast" under a second,
"moderate" under ten, "slow"); and the longest
series it finished within the measurement's time cap (0
when it did not finish 1,000 observations). The
measurements behind them are the cpt_runtimes and
cpt_invariances data sets.
cpt_install_engines() to install a whole family of
the engines this table reports on; cpt_detect() to run
one; cpt_register_method() to add your own.
cpt_methods() # which methods can draw a confidence interval? subset(cpt_methods(), ci)$methodcpt_methods() # which methods can draw a confidence interval? subset(cpt_methods(), ci)$method
Computes standard accuracy metrics comparing predicted changepoints to ground truth, including precision/recall/F1 with margin, covering metric, Hausdorff distance, adjusted Rand index, annotation error, and MAE/RMSE of matched locations.
cpt_metrics(pred, truth, n = NULL, margin = 5)cpt_metrics(pred, truth, n = NULL, margin = 5)
pred |
Predicted changepoint indices (integer vector), or a
|
truth |
Ground truth changepoint indices (integer vector). |
n |
Length of the series. Taken from |
margin |
Tolerance margin for matching (default 5). |
Precision/recall use a one-to-one matching: each truth may be
claimed by at most one prediction (predictions are scanned in order and
take the earliest unmatched truth within margin, which yields a
maximum matching for interval-structured problems). The covering metric
follows van den Burg and Williams (2020): the prediction-side partition is
always well defined, so an empty pred scores the covering of the
trivial single-segment partition rather than 0.
A tibble with one row and the columns below. “Higher” and
“lower” mark which direction is better, the same directions
cpt_benchmark() ranks by.
n, n_pred, n_truth
the series length and the two changepoint counts, after out-of-range indices are dropped.
precision, recall, f1
higher is
better. The fraction of predictions that matched a truth, the
fraction of truths that were matched, and their harmonic mean,
all under the one-to-one matching within margin, so they
score whether a change was found, not how precisely it was
located.
coveringhigher is better, in . The
segmentation covering metric: each true segment's best Jaccard
overlap with a predicted segment, averaged weighted by segment
length. Unlike F1 it needs no margin and degrades smoothly with
location error. It has a floor: an empty prediction
scores about for true changepoints (0.5
for one change in the middle), so covering is not comparable across
problems with different and should not be averaged over
them.
cpt_benchmark() ranks within each dataset instead
for exactly that reason.
covering_floor, covering_scaled
the covering
an empty prediction scores on this truth (the sum of the squared
true segment shares, when the segments are equal),
and covering rescaled so that the floor is 0 and a perfect
segmentation 1, : comparable
across problems with different . NA when
, where the floor is already 1.
hausdorfflower is better, in observations. The largest distance from any changepoint on either side to the nearest one on the other: a worst-case location error, so one badly placed changepoint dominates it.
rand_indexhigher is better. The adjusted Rand index between the two segment labellings: 1 for identical partitions, 0 for chance agreement, and negative for worse than chance.
annotation_errorlower is better. A count
difference only: abs(n_pred - n_truth). It says nothing
about location, so a segmentation with the right number of
changepoints in entirely the wrong places scores a perfect
0. Read it beside covering or hausdorff, never
alone.
mae_matched, rmse_matched
lower is better, in
observations. Mean absolute and root-mean-square location error over
the matched pairs only, so they describe how well the changepoints
that were found are placed and ignore the ones that were missed.
NA when nothing matched.
precision, recall and f1 are
thresholded at margin: a changepoint off by
margin counts as found and one off by margin + 1 as
missed, so they can move from 1 to 0 on a one-observation change.
covering, hausdorff, rand_index and the matched
errors are continuous in the location.
Three of the twelve columns are ratios with a zero denominator when one side is empty, and the row does not resolve them all the same way, so the conventions are worth stating rather than inferring from a benchmark table:
Both empty. The segmentation is exactly right:
precision, recall, f1, covering and
rand_index are all 1 and annotation_error is 0. (A
metric that scored this 0 was a 0.4.0 bug.)
One side empty. precision and recall are
0 rather than NA (finding nothing where there was a
change, and finding a change where there was none, both score badly),
and so is f1. rand_index is 0 for the same reason.
Nothing matched. hausdorff,
mae_matched and rmse_matched are NA, because
they are distances and there is no pair to measure. They are also
NA whenever either side is empty. This is the one place the
row mixes conventions: an all-wrong answer gives
f1 = 0 and mae_matched = NA in the same row.
cpt_benchmark() treats an NA as the worst rank
rather than dropping it.
An index outside 1..(n - 1) is dropped with a warning: locations
follow the "left" convention, and an out-of-range one would
corrupt the partition metrics rather than merely miss.
cpt_metrics_annotated() for scoring against
multiple annotators, and cpt_benchmark() to run a
method-by-dataset grid on these metrics.
cpt_metrics(c(100, 200), c(100, 200), n = 300) cpt_metrics(c(101, 205), c(100, 200), n = 300, margin = 5)cpt_metrics(c(100, 200), c(100, 200), n = 300) cpt_metrics(c(101, 205), c(100, 200), n = 300, margin = 5)
Computes averaged covering and F1 scores against multiple annotation sets, as used in the Turing Change Point Dataset benchmark.
cpt_metrics_annotated(pred, annotations, n = NULL, margin = 5)cpt_metrics_annotated(pred, annotations, n = NULL, margin = 5)
pred |
Predicted changepoint indices, or a |
annotations |
A list of ground-truth annotation vectors. |
n |
Length of the series; taken from |
margin |
Tolerance margin (default 5). |
A tibble with one row: n, n_annotators,
n_pred, and the four metrics this averages:
precision, recall, f1 and covering.
Each is a plain unweighted mean of the per-annotator value from
cpt_metrics(), over all n_annotators of them.
This is a narrower table than cpt_metrics()
returns, so a call moved from one to the other loses columns:
n_truth (there is no single truth), and the location metrics
hausdorff, mae_matched, rmse_matched,
rand_index and annotation_error.
The three distance metrics are omitted for a reason worth stating,
because it is not obvious: they are NA whenever an annotator
shares no matched pair with the prediction, so averaging them would
quietly divide by fewer annotators than n_annotators reports.
Measured on three annotators against one prediction
(list(c(100, 200), integer(0), 150) at ),
mae_matched was available for one of the three and
hausdorff for two, while f1 and covering were
finite for all three. Score those per annotator with
cpt_metrics() and combine them yourself if you want
them, so the divisor is yours to choose.
covering and f1 are the pair the Turing Change Point
Dataset benchmark reports, which is why they are the ones averaged
here; precision and recall come along as F1's parts.
cpt_metrics() for the full single-truth table
and what each column means.
# two annotators who disagree slightly about where the change is cpt_metrics_annotated(c(100, 200), annotations = list(c(98, 200), c(100, 203)), n = 300, margin = 5)# two annotators who disagree slightly about where the change is cpt_metrics_annotated(c(100, 200), annotations = list(c(98, 200), c(100, 203)), n = 300, margin = 5)
Inverts cpt_power(): searches for the change size at which
the detector reaches a target power. The study-design counterpart of a
power curve, and the number that belongs in a pre-registration.
cpt_min_detectable( n, sigma = 1, method = "pelt", power = 0.8, range = c(0.1, 5), n_sim = 100, tolerance = 5, change_in = "mean", location = 0.5, noise = "gauss", rho = 0, df = 3, tol = 0.05, max_iter = 12, seed = NULL, ... ) ## S3 method for class 'ggcpt_min_detectable' tidy(x, ...) ## S3 method for class 'ggcpt_min_detectable' print(x, ...)cpt_min_detectable( n, sigma = 1, method = "pelt", power = 0.8, range = c(0.1, 5), n_sim = 100, tolerance = 5, change_in = "mean", location = 0.5, noise = "gauss", rho = 0, df = 3, tol = 0.05, max_iter = 12, seed = NULL, ... ) ## S3 method for class 'ggcpt_min_detectable' tidy(x, ...) ## S3 method for class 'ggcpt_min_detectable' print(x, ...)
n |
Series length. |
sigma |
Noise standard deviation. Defaults to |
method |
Detection method. Defaults to |
power |
Target detection probability. Defaults to |
range |
Search range for the change size, in standard deviations.
Defaults to |
n_sim |
Replicates per evaluation. Defaults to |
tolerance |
A detection counts as finding the change when it falls
within this many positions of it. Defaults to |
change_in |
What changes. Defaults to |
location |
Changepoint position, as a fraction of |
noise |
Noise model, passed to |
rho |
AR(1) parameter when |
df |
Degrees of freedom when |
tol |
Bisection tolerance on the change size. Defaults to
|
max_iter |
Maximum bisection steps. Defaults to |
seed |
Optional seed. The seed is scoped to this call:
|
... |
Ignored. |
x |
A |
A list with jump (the smallest change reaching
power), achieved_power, mc_se, and the
trace of evaluations, with print() and tidy()
(one row) methods.
cpt_power().
# n_sim = 10, max_iter = 3: the search is n_sim detector fits per # iteration, and n_sim = 30 with max_iter = 4 measured 5.4 s against # CRAN's 5 s example budget. Raise both for a usable answer. cpt_min_detectable(n = 200, n_sim = 10, max_iter = 3, seed = 1)# n_sim = 10, max_iter = 3: the search is n_sim detector fits per # iteration, and n_sim = 30 with max_iter = 4 measured 5.4 s against # CRAN's 5 s example budget. Raise both for a usable answer. cpt_min_detectable(n = 200, n_sim = 10, max_iter = 3, seed = 1)
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.
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"), ...)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"), ...)
method |
Which sequential detector:
|
baseline |
A numeric vector (or, for |
alpha |
Target false-alarm probability for |
arl0 |
Target in-control average run length for |
cpm_type |
Statistic for |
patience |
Target patience (average run length) for |
deltas |
Shift sizes, in baseline standard deviations, mixed over by
|
reset |
After an alarm, restart the detector ( |
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 |
thresh |
Threshold rule for |
mc_reps |
Monte Carlo repetitions for the |
... |
Additional arguments passed to the engine's constructor. |
x |
A |
object |
A |
plot_type |
|
A ggcpt_monitor object: a list carrying the detector's
state between calls, so it is meant to be passed to
cpt_update() and re-assigned rather than read field by
field. The parts worth reading are
alarmsthe tibble alarms() and
tidy() return: one row per
alarm, with time, statistic and
threshold. Empty (zero rows) until something fires.
thow many observations the monitor has consumed
through cpt_update(), not counting the
baseline; an alarm's time is on this same clock. A monitor
built by cpt_replay() also carries offset,
the number of leading observations it trained on, so
time + offset is a position in the replayed series
(cpt_delay() applies it for you).
dataevery monitored observation so far, baseline
excluded (the first coordinate, for a multivariate monitor),
which is what autoplot() draws.
method, alpha, n_baseline,
reset, relearn
the settings this call fixed,
kept so a later cpt_update() cannot silently disagree
with them.
statethe detector's internal statistics. Engine
internals: their shape differs by method and is not part
of the interface.
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
the increment is the likelihood ratio
, which has unit mean under the null; the running
statistic is ; the shifts are combined by averaging,
; and an alarm is raised
the first time .
The averaging is not a detail. Under the null is a
mean-zero martingale, so optional stopping at the alarm time
gives : 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.
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.
cpt_update(), alarms(),
cpt_replay(), cpt_delay().
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)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)
Ten replicates of a 300-point series with mean changes of two marginal
standard deviations at 100 and 200, under independent Gaussian noise,
heavy-tailed noise (, scaled to unit variance), AR(1) noise with
and heteroscedastic noise (standard deviations 0.5, 1
and 2.5 by segment), for every univariate engine at its default and at
each setting of its noise-model argument. A recommendation is a call,
not a name: smuce and smuce with family = "hsmuce"
are different detectors.
cpt_noise_benchmarkcpt_noise_benchmark
A tibble with one row per engine, setting and regime:
the engine and the argument setting
("default" or the argument as written).
the cpt_detect() call the row measures.
"iid", "heavy", "ar1" or
"hetero".
replicates that ran.
mean number of the two real changes found within ten positions.
mean number of reported changepoints more than ten positions from either.
data-raw/measure_engines.R (part noise).
Other measurement tables:
cpt_calibration,
cpt_data_types,
cpt_invariances,
cpt_null_sizes,
cpt_runtimes
ar <- subset(cpt_noise_benchmark, regime == "ar1") ar[order(ar$fp), c("call", "hits", "fp")]ar <- subset(cpt_noise_benchmark, regime == "ar1") ar[order(ar$fp), c("call", "hits", "fp")]
When a detection comes back empty, the useful question is whether a
change of the size you care about would have been found. This runs
cpt_min_detectable() at the fit's own length, method and
penalty, with the noise level estimated from the series, and reports the
smallest shift detected with the requested power: changes smaller than
that could well be there and missed.
cpt_null_power(fit, power = 0.8, n_sim = 50, seed = NULL, ...) ## S3 method for class 'ggcpt_null_power' print(x, ...) ## S3 method for class 'ggcpt_null_power' tidy(x, ...)cpt_null_power(fit, power = 0.8, n_sim = 50, seed = NULL, ...) ## S3 method for class 'ggcpt_null_power' print(x, ...) ## S3 method for class 'ggcpt_null_power' tidy(x, ...)
fit |
A |
power |
Target power. Defaults to |
n_sim |
Simulations per power evaluation. Defaults to |
seed |
Optional seed, scoped to this call. |
... |
Further arguments for |
x |
A |
A ggcpt_null_power list with n, sigma (the
noise level used), jump (the smallest detectable change, in the
data's units), jump_sd (the same in noise standard deviations),
change_in (the fit's change type, which sets what jump
measures: a shift in the mean, a rise in the standard deviation, both,
or a trend, as cpt_power() defines them), power,
method and constant (TRUE when the series has no
variation, in which case nothing is simulated). With print() and
tidy() methods. A formula fit is refused: the simulation has no
covariates to draw.
Other inference:
cpt_assumptions(),
cpt_attribute_event(),
cpt_effect(),
cpt_gof(),
cpt_robustness(),
cpt_test_at(),
cpt_test_null()
set.seed(1) fit <- cpt_detect(rnorm(100), method = "pelt") cpt_null_power(fit, n_sim = 20, seed = 1)set.seed(1) fit <- cpt_detect(rnorm(100), method = "pelt") cpt_null_power(fit, n_sim = 20, seed = 1)
Independent Gaussian noise with no changepoint anywhere, at 1,000 (50 replicates), 10,000 (10) and 100,000 (6) observations, for the engines the runtime table shows finishing that length quickly. Every changepoint reported is a false alarm.
cpt_null_sizescpt_null_sizes
A tibble with one row per engine and length:
the engine.
the series length.
replicates that ran.
share of replicates reporting at least one changepoint.
mean number of changepoints reported.
data-raw/measure_engines.R (part null).
Other measurement tables:
cpt_calibration,
cpt_data_types,
cpt_invariances,
cpt_noise_benchmark,
cpt_runtimes
subset(cpt_null_sizes, n == max(n))subset(cpt_null_sizes, n == max(n))
Helper to construct standard penalty values for use with changepoint detection methods. Returns a numeric penalty value.
cpt_penalty(type, n = NULL, k = 1, value = NULL, alpha = 1.01, series = NULL)cpt_penalty(type, n = NULL, k = 1, value = NULL, alpha = 1.01, series = NULL)
type |
Penalty type: |
n |
Series length (at least 3 for the |
k |
Number of parameters per changepoint (typically 2 for
mean+variance, 1 for mean-only). Defaults to 1. The |
value |
Numeric value for |
alpha |
Exponent of the strengthened SIC ( |
series |
The series a learned penalty is predicted for. Required
only when |
A numeric penalty value.
The same penalty name may be interpreted differently by different engines:
changepoint-based methods (PELT, BinSeg, SegNeigh, AMOC):
accept character penalties ("MBIC", "BIC", "AIC",
"Hannan-Quinn", "None") and pass them to the upstream
changepoint package. A numeric penalty is translated to that
package's penalty = "Manual" plus pen.value. The one
exception is Segment Neighbourhood, for which changepoint does
not implement MBIC: cpt_detect(method = "segneigh") and
cpt_wrapper(cp_method = "SegNeigh") therefore fall back to
"SIC" when the default penalty is left in place, so a segneigh
result is not directly penalty-comparable with a PELT one. Pass
penalty explicitly to pin it. For a change in mean
these engines also read the penalty on the data's own scale rather
than a standardised one; see the scale-sensitivity section of
cpt_detect.
Functional-pruning methods (fpop, cpop,
decafs): accept numeric penalties only. When a character penalty
is supplied via cpt_detect(), it is resolved to a numeric value
using cpt_penalty() before dispatch.
Search-based methods (WBS, WBS2, NOT, MOSUM, IDetect,
TGUH): use internal model-selection criteria (e.g., sSIC, threshold)
and generally ignore the penalty argument. Specify
thresholds via the wrapper's own arguments.
fastcpd takes its penalty as beta, on its
own scale, and defaults to its native "MBIC".
cpt_detect() forwards a numeric penalty as
beta, and translates the three names the two packages share
("MBIC", "BIC"/"SIC", "MDL"). Any other
character penalty ("AIC", "Hannan-Quinn",
"sSIC", "None") has no fastcpd equivalent and
is left to the engine's default rather than being silently
approximated; pass beta yourself to pin it. Whatever is used
is recorded on the result, so print() and glance()
report the penalty of the fit in hand.
Inference/Bayesian methods (smuce, bcp,
bocpd, beast, cpm, sn): are tuned by a
significance level, posterior-probability threshold, hazard, or
average run length rather than a penalty; see each wrapper.
MBIC in cpt_penalty() is a BIC-type penalty
that adds a combinatorial term for the number of ways k
changepoints can be placed in n observations,
. It is deliberately stronger
than "BIC". It is not the modified BIC of Zhang and
Siegmund (2007), whose penalty is
on the
log-likelihood scale (equivalently
on the deviance scale,
which is how cpt_select() states it and the scale its
cost column uses). It depends on the segment lengths
and so cannot be expressed by a function of n and
k alone. Use the character "MBIC" with
changepoint-based methods to get the engine's native MBIC, and
cpt_select(criterion = "mbic") for the Zhang-Siegmund one.
cpt_penalty("BIC", n = 100) cpt_penalty("AIC", n = 100) cpt_penalty("Manual", value = 5)cpt_penalty("BIC", n = 100) cpt_penalty("AIC", n = 100) cpt_penalty("Manual", value = 5)
Simulates replicate series under a scenario and reports how often the detector finds the change, how accurately it locates it, and how often it reports changes that are not there. This is the calculation that should precede an analysis, and the one applied papers are increasingly asked for.
cpt_power( n, jump, sigma = 1, method = "pelt", location = 0.5, n_sim = 200, tolerance = 5, change_in = "mean", noise = "gauss", rho = 0, df = 3, seed = NULL, parallel = TRUE, family = "gaussian", baseline = NULL, ... ) ## S3 method for class 'ggcpt_power' tidy(x, ...) ## S3 method for class 'ggcpt_power' print(x, ...) ## S3 method for class 'ggcpt_power' autoplot(object, ...)cpt_power( n, jump, sigma = 1, method = "pelt", location = 0.5, n_sim = 200, tolerance = 5, change_in = "mean", noise = "gauss", rho = 0, df = 3, seed = NULL, parallel = TRUE, family = "gaussian", baseline = NULL, ... ) ## S3 method for class 'ggcpt_power' tidy(x, ...) ## S3 method for class 'ggcpt_power' print(x, ...) ## S3 method for class 'ggcpt_power' autoplot(object, ...)
n |
Series length. |
jump |
Size of the change, in units of |
sigma |
Noise standard deviation. Defaults to |
method |
Detection method. Defaults to |
location |
Changepoint position, as a fraction of |
n_sim |
Replicates per scenario. Defaults to |
tolerance |
A detection counts as finding the change when it falls
within this many positions of it. Defaults to |
change_in |
What changes. Defaults to |
noise |
Noise model, passed to |
rho |
AR(1) parameter when |
df |
Degrees of freedom when |
seed |
Optional seed. The seed is scoped to this call:
|
parallel |
Use |
family |
|
baseline |
The family's parameter before the change, for a
non-Gaussian |
... |
Additional arguments passed to |
x |
A |
object |
A |
A ggcpt_power object: a tibble with one row per scenario,
with columns n, jump, sigma, location,
power (proportion of replicates detecting the change within
tolerance), mc_se (the Monte Carlo standard error of that
proportion), mean_abs_error (location error among detections;
NaN when no replicate detected a changepoint within
tolerance of the true one, because there is no distance to
average, and power reads 0 in the same row),
false_positives (mean number of extra changepoints per
replicate) and n_sim; with print() and
autoplot().
A seeded call is reproducible for a given future::plan(),
and not across plans. Under a parallel plan the replicates' random numbers
come from future.apply's parallel-safe L'Ecuyer streams, derived
from seed; run sequentially they come from the calling stream that
seed set. Both are deterministic, and they are not the same
numbers. Measured on cpt_power(n = c(100, 200), jump = 0.5,
n_sim = 8, seed = 11): power = 0.25, 0.125 sequentially and
0, 0.375 on two workers. The scenario is named because the
numbers depend on it and on the worker count; what does not depend on
either is that the two disagree.
So the guarantee is: same seed and same plan, same answer, every time,
whichever plan it is. If a power figure needs to be reproducible by
someone else, pin the execution as well as the seed: pass
parallel = FALSE, or state the plan alongside the seed. Raising
n_sim narrows the gap, because it is Monte Carlo error rather
than disagreement: both estimates are of the same quantity, and
mc_se says how precisely.
This is specific to cpt_power(), which is the one function here
whose parallel tasks consume random numbers. The other six that dispatch
on future::plan() (cpt_benchmark(),
cpt_batch(), cpt_consensus(),
cpt_influence(), cpt_sensitivity() and
ggcpt_compare()) farm out work that is deterministic
given its input, and were measured to return identical results under a
sequential and a two-worker plan, stochastic engines included.
cpt_min_detectable(), cpt_scenarios(),
cpt_simulate().
pw <- cpt_power(n = 200, jump = c(0.5, 1, 2), n_sim = 30, seed = 1) pw ggplot2::autoplot(pw)pw <- cpt_power(n = 200, jump = c(0.5, 1, 2), n_sim = 30, seed = 1) pw ggplot2::autoplot(pw)
Turns the capability matrix and the package's measurements into an
answer. Given what the analyst knows about their problem (how many
dimensions, what kind of change, what the noise and the data look like,
how long the series is, how many changes they expect, whether they need
uncertainty or an online alarm), this returns the methods that fit, as
calls, with the power and false-alarm rate measured for each in that
situation, a reason and the caveats. It is a decision table, not a
model: everything it knows is in cpt_methods() and the
measurement tables (cpt_noise_benchmark,
cpt_data_types, cpt_runtimes), and making that
explicit and printable is the point.
cpt_recommend( dimension = c("univariate", "multivariate"), change_in = "mean", noise = c("iid", "heavy", "autocorrelated", "heteroscedastic"), n = NULL, need_uncertainty = FALSE, online = FALSE, installed_only = FALSE, n_expected = NULL, data_type = c("continuous", "counts", "binary", "proportion"), family = NULL, fit = NULL, jump = NULL ) ## S3 method for class 'ggcpt_recommendation' tidy(x, ...) ## S3 method for class 'ggcpt_recommendation' print(x, top = 5, ...) ## S3 method for class 'ggcpt_recommendation' autoplot(object, top = 15, ...)cpt_recommend( dimension = c("univariate", "multivariate"), change_in = "mean", noise = c("iid", "heavy", "autocorrelated", "heteroscedastic"), n = NULL, need_uncertainty = FALSE, online = FALSE, installed_only = FALSE, n_expected = NULL, data_type = c("continuous", "counts", "binary", "proportion"), family = NULL, fit = NULL, jump = NULL ) ## S3 method for class 'ggcpt_recommendation' tidy(x, ...) ## S3 method for class 'ggcpt_recommendation' print(x, top = 5, ...) ## S3 method for class 'ggcpt_recommendation' autoplot(object, top = 15, ...)
dimension |
|
change_in |
What kind of change is expected: any value accepted by
|
noise |
Noise structure: |
n |
Series length. Methods the runtime table saw fail to finish at that length are left out (and listed), and the slow ones carry a caveat. Optional. |
need_uncertainty |
Does the answer have to come with a confidence
interval or significance region? Defaults to |
online |
Is detection sequential (alarms as data arrive) rather than
retrospective? Defaults to |
installed_only |
Restrict to engines that are installed. Defaults to
|
n_expected |
How many changes you expect, if you know. The
single-change designs ( |
data_type |
What the values are: |
family |
Optional distribution family the method must fit (see
|
fit |
Optional |
jump |
Optional expected change size, in noise standard deviations.
With |
x |
A |
... |
Ignored. |
top |
How many candidates to print. Defaults to |
object |
A |
A ggcpt_recommendation tibble ordered by suitability, with
columns method, engine, installed, score,
tie (candidates with the same score share a number: the
recommender cannot tell them apart on what was supplied), call
(the cpt_detect() call to run, including the noise-model or
family argument the recommendation depends on), hits and
false_positives (measured in the stated regime: mean real
changes found out of two, and mean spurious ones), power (when
jump is given), why and caveat. print()
reads as advice and autoplot() shows the scores and the ties.
Where the method was measured in the stated noise regime, the score
starts from , where is the expected number of errors
per series in that benchmark (real changes missed plus false alarms),
taking the method's best setting of its noise-model argument (which is
then the one in call). A method not measured there starts at 1.
Then: minus 3 for a single-change design unless n_expected = 1;
minus the log of one plus its measured false positives on the stated
data type, and plus 1.5 if it fits that data type's family; plus 1 for a
location interval and 0.5 for a posterior when uncertainty is needed;
at , plus 0.5 for a fast engine and minus 1 for a slow
one; and small tie-breakers for the general-purpose methods (0.25) and
for an installed engine (0.1). Sort by false_positives instead if
a false alarm costs you more than a miss.
cpt_methods(), cpt_consensus(),
cpt_cite().
cpt_recommend(noise = "autocorrelated") cpt_recommend(data_type = "counts", n_expected = 2) cpt_recommend(dimension = "multivariate", change_in = "covariance")cpt_recommend(noise = "autocorrelated") cpt_recommend(data_type = "counts", n_expected = 2) cpt_recommend(dimension = "multivariate", change_in = "covariance")
The interval-valued methods (currently nsp_wrapper())
return regions rather than points: each is guaranteed to contain at least
one changepoint at a prescribed global significance level. A
region is a different object from a confidence interval around an
estimate, so it lives in its own slot and has its own accessor rather
than being folded into tidy().
cpt_regions(x)cpt_regions(x)
x |
A |
A tibble with columns start, end (positions),
length, and, when the result carries a time index,
start_index/end_index on the original scale. Any further
columns the engine supplied are carried through after those:
nsp_wrapper() adds value, the region's statistic.
A zero-row tibble when the result carries no regions.
nsp_wrapper(), geom_cpt_region(),
cpt_confint().
set.seed(2026) fit <- as_ggcpt(50, c(rnorm(50), rnorm(50, 4)), regions = data.frame(start = 45, end = 56)) cpt_regions(fit)set.seed(2026) fit <- as_ggcpt(50, c(rnorm(50), rnorm(50, 4)), regions = data.frame(start = 45, end = 56)) cpt_regions(fit)
Teaches cpt_detect() about a detector this package does not
(and often cannot) depend on: an engine that is not on CRAN, a Python
detector reached through reticulate, a deep-learning model, a
proprietary in-house method, or a hand-curated set of changepoints. The
registered method then works with everything built on the ggcpt
contract: autoplot(), the geoms, tidy()/glance()/
augment(), cpt_metrics(), ggcpt_compare(),
cpt_stability(), cpt_consensus(), cpt_benchmark()
and cpt_report().
cpt_register_method( name, fn, change_in = "mean", engine = "user", citation = NULL, capabilities = list(), cp_convention = c("left", "right"), overwrite = FALSE ) cpt_unregister_method(name) cpt_registered_methods()cpt_register_method( name, fn, change_in = "mean", engine = "user", citation = NULL, capabilities = list(), cp_convention = c("left", "right"), overwrite = FALSE ) cpt_unregister_method(name) cpt_registered_methods()
name |
Method name, as it will be passed to |
fn |
A function called as A returned |
change_in |
Character vector of |
engine |
Name of the package or system supplying the detector, for
display in |
citation |
Optional citation string returned by
|
capabilities |
Optional named list of capability flags overriding the
defaults (all |
cp_convention |
|
overwrite |
Replace an existing registration of the same name?
Defaults to |
Invisibly, the method name.
cpt_registered_methods() returns a tibble with one row per
registered method (columns method, change_in,
engine, has_citation), or a zero-row tibble when none are
registered.
A registered method is visibly user-supplied: cpt_methods() gives it
status = "registered", print() on its results marks it, and
cpt_cite() reports the citation you supplied or states that none
was given. The package validates the shape of what your function
returns (through as_ggcpt(), which runs the same contract
checks as every built-in wrapper); it does not and cannot validate the
method.
as_ggcpt() to turn changepoints into a result
object without registering a method;
cpt_unregister_method();
cpt_registered_methods().
# A deliberately trivial detector: split at the largest jump. cpt_register_method( "biggest_jump", fn = function(x, ...) which.max(abs(diff(x))), change_in = "mean", engine = "example", citation = "No citation supplied (illustration only)." ) set.seed(1) fit <- cpt_detect(c(rnorm(50), rnorm(50, 5)), method = "biggest_jump") fit cpt_unregister_method("biggest_jump")# A deliberately trivial detector: split at the largest jump. cpt_register_method( "biggest_jump", fn = function(x, ...) which.max(abs(diff(x))), change_in = "mean", engine = "example", citation = "No citation supplied (illustration only)." ) set.seed(1) fit <- cpt_detect(c(rnorm(50), rnorm(50, 5)), method = "biggest_jump") fit cpt_unregister_method("biggest_jump")
Runs a whole series through a monitor in one call, so the alarm timeline
of an online method can be studied retrospectively without hand-rolling
the update loop. This is the honest version of what 0.4.0's cpm,
ocd and bocpd wrappers do implicitly: it reports
alarms, which arrive after the change, rather than pretending they
are estimated changepoint locations.
cpt_replay(x, method = c("edetector", "cpm", "ocd"), baseline = NULL, ...)cpt_replay(x, method = c("edetector", "cpm", "ocd"), baseline = NULL, ...)
x |
A numeric vector, or a matrix with rows as time points. |
method |
Sequential detector; see |
baseline |
Number of leading observations used as pre-change training
data (an integer), or an explicit baseline vector. Defaults to
|
... |
Additional arguments passed to |
A ggcpt_monitor that has already consumed the series:
the same object cpt_monitor() returns, described
there, with alarms filled in for whatever fired.
cpt_delay(), cpt_monitor().
set.seed(2026) mon <- cpt_replay(c(rnorm(200), rnorm(200, 3)), method = "edetector") alarms(mon)set.seed(2026) mon <- cpt_replay(c(rnorm(200), rnorm(200, 3)), method = "edetector") alarms(mon)
Assembles everything a reader needs to judge a changepoint result into one artifact: the method and its citation, the penalty, the number and locations of the changepoints with intervals where available, the segment table, stability and diagnostics if they were computed, and the session information. Reproducibility and correct attribution in one call.
cpt_report( object, format = c("md", "text", "gt", "json"), file = NULL, stability = NULL, events = NULL, confint = TRUE, session = TRUE )cpt_report( object, format = c("md", "text", "gt", "json"), file = NULL, stability = NULL, events = NULL, confint = TRUE, session = TRUE )
object |
A |
format |
|
file |
Optional path to write to. The report is returned invisibly
when a file is written. Ignored for |
stability |
Optional |
events |
Optional |
confint |
Include a |
session |
Include |
A character vector of report lines (or a gt table when
format = "gt").
set.seed(2026) fit <- cpt_detect(c(rnorm(60), rnorm(60, 4)), method = "pelt") cat(cpt_report(fit, session = FALSE), sep = "\n")set.seed(2026) fit <- cpt_detect(c(rnorm(60), rnorm(60, 4)), method = "pelt") cat(cpt_report(fit, session = FALSE), sep = "\n")
Re-runs a detector under each setting of its noise-model argument
(family for stepR's SMUCE, variant for NSP, the cost
for the changepoint engines, ...) and reports which changepoints
appear under every setting and which only under some. A changepoint that
survives a change of noise model is evidence; one that survives a
bootstrap (cpt_stability()) or a change of algorithm
(cpt_consensus()) may only be a feature of the noise, which
resampling and other algorithms reproduce.
cpt_robustness( x, method = "pelt", over = "noise_model", settings = NULL, margin = 5, seed = NULL, ... ) ## S3 method for class 'ggcpt_robustness' print(x, ...) ## S3 method for class 'ggcpt_robustness' tidy(x, ...) ## S3 method for class 'ggcpt_robustness' autoplot(object, ...)cpt_robustness( x, method = "pelt", over = "noise_model", settings = NULL, margin = 5, seed = NULL, ... ) ## S3 method for class 'ggcpt_robustness' print(x, ...) ## S3 method for class 'ggcpt_robustness' tidy(x, ...) ## S3 method for class 'ggcpt_robustness' autoplot(object, ...)
x |
A numeric series, or a |
method |
The detector, when |
over |
What to vary. Only |
settings |
Optional named list of settings, each a list of
arguments for |
margin |
Positions within which two changepoints count as the same.
Defaults to |
seed |
Optional seed, scoped to this call. |
... |
Further arguments for every |
object |
A |
A ggcpt_robustness object: a list with settings
(one row per setting: setting, n_cp, powered and
error), changepoints (one row per changepoint of the
reference setting: cp, found_by (how many other powered
settings find it within margin), of (how many powered
alternatives there are) and survives), union and
intersection (distinct locations found by any and by every
powered setting) and fits. With print() and
autoplot().
A setting that finds nothing where the reference finds several is not a
vote against them: measured, NSP's variant = "ar" removes the
false positives of autocorrelated noise by removing detection altogether
(0 of 2 real changes found). Such a setting is marked
powered = FALSE and left out of found_by.
cpt_assumptions(), cpt_sensitivity()
for sweeping any argument.
Other inference:
cpt_assumptions(),
cpt_attribute_event(),
cpt_effect(),
cpt_gof(),
cpt_null_power(),
cpt_test_at(),
cpt_test_null()
set.seed(1) x <- c(rnorm(100), rnorm(100, 2)) + as.numeric(arima.sim(list(ar = 0.6), 200)) cpt_robustness(x, method = "pelt")set.seed(1) x <- c(rnorm(100), rnorm(100, 2)) + as.numeric(arima.sim(list(ar = 0.6), 200)) cpt_robustness(x, method = "pelt")
One timed cpt_detect() call per engine and length, each in its own
R process running an installed (byte-compiled) build, after a warm-up
call, so the time is the fit and not loading or compiling anything, with
a time cap of 120 seconds (300 at a million). A length is attempted only
when the previous one finished in under ten seconds.
One run per cell: this answers "will it finish?", and is not a basis for
claiming one engine is faster than another by a given factor.
cpt_runtimescpt_runtimes
A tibble with one row per engine and length attempted:
the method, as cpt_detect() takes it.
the series length: 1,000, 10,000, 100,000 or 1,000,000, with four mean changes of two noise standard deviations (three coordinates for the multivariate engines).
elapsed time of the fit.
changepoints reported (four are real; a single-change method reports one).
"ok", "timeout" or "error".
data-raw/measure_engines.R (part runtime).
cpt_methods()'s cost and max_n
columns, cpt_recommend().
Other measurement tables:
cpt_calibration,
cpt_data_types,
cpt_invariances,
cpt_noise_benchmark,
cpt_null_sizes
subset(cpt_runtimes, n == 1e5 & status == "ok")subset(cpt_runtimes, n == 1e5 & status == "ok")
Sweeps a multiscale detector's bandwidth and returns the statistic at every (location, bandwidth) pair. The resulting heatmap answers the question a single-bandwidth fit cannot: at which resolutions does this feature exist? A change that is significant only at a wide bandwidth is a slow shift; one that appears only at a narrow bandwidth is a spike.
cpt_scale_space(x, bandwidths = NULL, method = c("mosum", "npmojo"), ...) ggcpt_scale_space(x, bandwidths = NULL, method = c("mosum", "npmojo"), ...)cpt_scale_space(x, bandwidths = NULL, method = c("mosum", "npmojo"), ...) ggcpt_scale_space(x, bandwidths = NULL, method = c("mosum", "npmojo"), ...)
x |
A numeric vector (or, for |
bandwidths |
Integer vector of bandwidths to sweep. Defaults to a
geometric grid between |
method |
Which engine to sweep: |
... |
Additional arguments passed to the engine at each bandwidth. |
cpt_scale_space() returns a tibble with index,
bandwidth, statistic, threshold,
significant (the statistic at that location and bandwidth
exceeds the threshold) and detected (the engine reported a
changepoint there at that bandwidth). The two differ: a location can
clear the threshold without surviving the engine's own pruning. ggcpt_scale_space() draws the heatmap with
the accepted changepoints overlaid.
set.seed(2026) x <- c(rnorm(300), rnorm(300, 2)) ss <- cpt_scale_space(x, bandwidths = c(20, 40, 80)) head(ss)set.seed(2026) x <- c(rnorm(300), rnorm(300, 2)) ss <- cpt_scale_space(x, bandwidths = c(20, 40, 80)) head(ss)
Builds the scenario grid a simulation study varies over, as data rather
than as nested loops, so it can be inspected, filtered, subsetted and
passed straight to cpt_benchmark().
cpt_scenarios( n = 500, jump = c(0.5, 1, 2), location = 0.5, noise = "gauss", rho = 0.5, change_in = "mean", n_rep = 1, seed = 1, as_datasets = TRUE )cpt_scenarios( n = 500, jump = c(0.5, 1, 2), location = 0.5, noise = "gauss", rho = 0.5, change_in = "mean", n_rep = 1, seed = 1, as_datasets = TRUE )
n |
Series lengths. |
jump |
Change sizes, in standard deviations. |
location |
Change positions, as fractions of |
noise |
Noise models; any value |
rho |
AR(1) parameters (used by |
change_in |
Change types. |
n_rep |
Replicates per scenario. Defaults to |
seed |
Base seed; replicate |
as_datasets |
Return simulated datasets in
|
A named list of datasets, or a tibble of scenarios when
as_datasets = FALSE.
cpt_power(), cpt_benchmark().
scen <- cpt_scenarios(n = 200, jump = c(1, 3), as_datasets = FALSE) scenscen <- cpt_scenarios(n = 200, jump = c(1, 3), as_datasets = FALSE) scen
Detection says where the regimes change; this fits your model to
each regime. Every segment of fit gets its own copy of
model, fitted by engine to that segment's rows, and the
result is a table with one fitted model per segment that
tidy(), glance() and predict() read.
cpt_segment_models(fit, model = NULL, data = NULL, engine = stats::lm, ...) ## S3 method for class 'ggcpt_segment_models' tidy(x, conf_level = 0.95, ...) ## S3 method for class 'ggcpt_segment_models' glance(x, ...) ## S3 method for class 'ggcpt_segment_models' print(x, ...)cpt_segment_models(fit, model = NULL, data = NULL, engine = stats::lm, ...) ## S3 method for class 'ggcpt_segment_models' tidy(x, conf_level = 0.95, ...) ## S3 method for class 'ggcpt_segment_models' glance(x, ...) ## S3 method for class 'ggcpt_segment_models' print(x, ...)
fit |
A |
model |
A formula. For a result from a formula fit it defaults to
that formula; for a series it defaults to |
data |
Optional data frame with one row per observation, supplying covariates the model uses. For a formula fit the covariates are taken from the result. |
engine |
The fitting function, called as |
... |
Further arguments for |
x |
A |
conf_level |
Confidence level for the coefficient intervals. |
A ggcpt_segment_models tibble with one row per segment:
segment, start, end, n and model (a
list-column of fitted models, NULL where the fit failed).
tidy() gives the coefficient table with a segment
column; glance() one row per segment with n,
sigma, r_squared, AIC, BIC and
logLik.
predict.ggcpt() to forecast from a segment,
tidy.ggcpt(what = "coefficients") for the coefficients
the detection itself implies.
Other segment models:
predict.ggcpt()
set.seed(1) d <- data.frame(x = runif(200)) d$y <- ifelse(seq_len(200) <= 100, 1 + 2 * d$x, 3 - d$x) + rnorm(200, 0, 0.3) fit <- cpt_detect(y ~ x, data = d, method = "strucchange") sm <- cpt_segment_models(fit) tidy(sm) glance(sm)set.seed(1) d <- data.frame(x = runif(200)) d$y <- ifelse(seq_len(200) <= 100, 1 + 2 * d$x, 3 - d$x) + rnorm(200, 0, 0.3) fit <- cpt_detect(y ~ x, data = d, method = "strucchange") sm <- cpt_segment_models(fit) tidy(sm) glance(sm)
Builds a ladder of candidate segmentations with
changepoints and scores each one, returning the chosen , the
criterion curve behind the choice, and the fitted result at that .
Five criteria are available, including the consistent sample-splitting
cross-validation of Zou, Wang and Li (2020) and the segment-length mBIC of
Zhang and Siegmund (2007).
cpt_select( x, method = "pelt", criterion = c("bic", "mbic", "aic", "crops_elbow", "cv", "stability"), k_max = 20, folds = 5, B = 100, change_in = "mean", index = NULL, seed = NULL, ... ) ## S3 method for class 'ggcpt_selection' print(x, ...) ## S3 method for class 'ggcpt_selection' tidy(x, ...) ## S3 method for class 'ggcpt_selection' autoplot( object, plot_type = c("criterion", "segmentation", "ladder"), max_facets = 12, ... )cpt_select( x, method = "pelt", criterion = c("bic", "mbic", "aic", "crops_elbow", "cv", "stability"), k_max = 20, folds = 5, B = 100, change_in = "mean", index = NULL, seed = NULL, ... ) ## S3 method for class 'ggcpt_selection' print(x, ...) ## S3 method for class 'ggcpt_selection' tidy(x, ...) ## S3 method for class 'ggcpt_selection' autoplot( object, plot_type = c("criterion", "segmentation", "ladder"), max_facets = 12, ... )
x |
A numeric vector, or a |
method |
Detection method used to build the candidate ladder.
Defaults to |
criterion |
Which criterion selects
|
k_max |
Largest number of changepoints considered. Defaults to
|
folds |
Folds for |
B |
Bootstrap replicates for |
change_in |
Passed to the detector, and inherited from The three closed-form criteria assume a change in the mean
whatever this is set to. |
index |
Optional time index (a vector of dates, or a |
seed |
Optional seed. The seed is scoped to this call:
|
... |
Additional arguments passed to |
object |
A |
plot_type |
|
max_facets |
Maximum number of rungs drawn by
|
A ggcpt_selection object: a list with
criterion_table (one row per candidate : k,
value, cost, chosen, and a cpts
list-column), k (the chosen number), fit (the
ggcpt at that ), criterion and data.
Methods: print(), tidy() and autoplot() with
plot_type = "criterion", "segmentation" or
"ladder".
Zou C, Wang G, Li R (2020). “Consistent selection of the number of change-points via sample-splitting.” The Annals of Statistics, 48(1), 413–439. doi:10.1214/19-AOS1814.
Zhang NR, Siegmund DO (2007). “A modified Bayes information criterion with applications to the analysis of comparative genomic hybridization data.” Biometrics, 63(1), 22–32. doi:10.1111/j.1541-0420.2006.00662.x.
Haynes K, Eckley IA, Fearnhead P (2017). “Computationally efficient changepoint detection for a range of penalties.” Journal of Computational and Graphical Statistics, 26(1), 134–143.
cpt_crops(), cpt_penalty(),
cpt_sensitivity().
set.seed(2026) x <- c(rnorm(80), rnorm(80, 4), rnorm(80, 1)) sel <- cpt_select(x, criterion = "bic", k_max = 6) sel ggplot2::autoplot(sel) ggplot2::autoplot(sel, plot_type = "ladder")set.seed(2026) x <- c(rnorm(80), rnorm(80, 4), rnorm(80, 1)) sel <- cpt_select(x, criterion = "bic", k_max = 6) sel ggplot2::autoplot(sel) ggplot2::autoplot(sel, plot_type = "ladder")
The parameter analogue of cpt_influence(): instead of asking
which observation drives the answer, it asks which setting does.
Runs the detector over a grid of tuning values and reports the detected
locations for each, which is the direct answer to the commonest reviewer
question about a changepoint analysis: "is this robust to the penalty?".
cpt_sensitivity(x, method = "pelt", over = list(), seed = NULL, ...) ## S3 method for class 'ggcpt_sensitivity' print(x, ...) ## S3 method for class 'ggcpt_sensitivity' tidy(x, ...) ## S3 method for class 'ggcpt_sensitivity' autoplot(object, ...)cpt_sensitivity(x, method = "pelt", over = list(), seed = NULL, ...) ## S3 method for class 'ggcpt_sensitivity' print(x, ...) ## S3 method for class 'ggcpt_sensitivity' tidy(x, ...) ## S3 method for class 'ggcpt_sensitivity' autoplot(object, ...)
x |
A numeric vector (the series), or a |
method |
Detection method. Taken from |
over |
A named list of parameter vectors to sweep. Every combination
is run, so keep the grid small:
|
seed |
Optional seed. The seed is scoped to this call:
|
... |
Additional arguments held fixed across the grid and passed to
|
object |
A |
A ggcpt_sensitivity object: a list with a grid
tibble (one row per setting: the parameter columns, n_cp, and a
cpts list-column), the data, and the swept parameter
names. Methods: print(), tidy() (one row per detected
changepoint) and autoplot() (a location heatmap over the grid).
cpt_influence(), cpt_select().
set.seed(2026) x <- c(rnorm(60), rnorm(60, 3)) s <- cpt_sensitivity(x, method = "pelt", over = list(penalty = c(2, 10, 40))) s ggplot2::autoplot(s)set.seed(2026) x <- c(rnorm(60), rnorm(60, 3)) s <- cpt_sensitivity(x, method = "pelt", over = list(penalty = c(2, 10, 40))) s ggplot2::autoplot(s)
Creates a synthetic time series with known changepoints for testing and benchmarking.
cpt_simulate( n, changepoints = integer(), change_in = c("mean", "var", "meanvar", "slope"), params = NULL, noise = c("gauss", "t", "ar1", "rw"), sd = 1, df = 3, rho = 0, seasonality = NULL, sd_trend = NULL, seed = NULL, family = c("gaussian", "poisson", "binomial", "exponential") ) rcpt(...)cpt_simulate( n, changepoints = integer(), change_in = c("mean", "var", "meanvar", "slope"), params = NULL, noise = c("gauss", "t", "ar1", "rw"), sd = 1, df = 3, rho = 0, seasonality = NULL, sd_trend = NULL, seed = NULL, family = c("gaussian", "poisson", "binomial", "exponential") ) rcpt(...)
n |
Length of the series. |
changepoints |
Integer vector of changepoint locations (last index of each segment before the change). |
change_in |
What changes: |
params |
A list of parameters per segment. For |
noise |
Noise type: |
sd |
Noise standard deviation, non-negative (for Gaussian and t;
t-noise is rescaled so its standard deviation is exactly |
df |
Degrees of freedom for t-noise; must exceed 2 so the variance exists. Defaults to 3. |
rho |
AR(1) autocorrelation parameter, strictly between -1 and 1 for
stationarity. Defaults to 0. Used only when |
seasonality |
Optional seasonal component added to the signal, as a
list with |
sd_trend |
Optional smoothly varying noise scale: a length-2 numeric
giving the multiplier on |
seed |
Optional seed for reproducibility. The seed is scoped to this
call: |
family |
The distribution of the observations: |
... |
Passed to |
A tibble with columns index, value, and seg_id.
The true changepoints are stored in the true_changepoints attribute.
Other test signals:
signal_blocks(),
signal_fms(),
signal_mix(),
signal_stairs(),
signal_teeth()
dat <- cpt_simulate(200, changepoints = c(100), change_in = "mean", params = c(0, 10), seed = 2022) attr(dat, "true_changepoints") # a seasonal series with a level shift, and one with drifting noise seasonal <- cpt_simulate(240, changepoints = 120, params = c(0, 3), seasonality = list(period = 12, amplitude = 2), seed = 1) drifting <- cpt_simulate(240, changepoints = 120, params = c(0, 3), sd_trend = c(0.5, 3), seed = 1) # counts whose rate doubles counts <- cpt_simulate(200, changepoints = 100, params = c(4, 8), family = "poisson", seed = 1)dat <- cpt_simulate(200, changepoints = c(100), change_in = "mean", params = c(0, 10), seed = 2022) attr(dat, "true_changepoints") # a seasonal series with a level shift, and one with drifting noise seasonal <- cpt_simulate(240, changepoints = 120, params = c(0, 3), seasonality = list(period = 12, amplitude = 2), seed = 1) drifting <- cpt_simulate(240, changepoints = 120, params = c(0, 3), sd_trend = c(0.5, 3), seed = 1) # counts whose rate doubles counts <- cpt_simulate(200, changepoints = 100, params = c(4, 8), family = "poisson", seed = 1)
The order in which candidate changepoints entered the model, with the contrast (or split criterion) at each step. Binary segmentation splits recursively, WBS/WBS2/NOT/TGUH rank random intervals; in every case the final answer is a prefix of a path, and seeing the path shows how decisively each changepoint beat the next.
cpt_solution_path(object) ggcpt_solution_path(object, max_steps = 40)cpt_solution_path(object) ggcpt_solution_path(object, max_steps = 40)
object |
A |
max_steps |
Longest prefix of the path drawn. Defaults to |
cpt_solution_path() returns a tibble with step,
cp, contrast and, for interval-based searches,
start/end of the interval that proposed it, plus a
selected flag marking the changepoints in the final model.
ggcpt_solution_path() draws it.
contrast is the engine's own ordering criterion, and it is a
different quantity per engine: a penalty value for
binseg/segneigh (from
changepoint::pen.value.full()), for wbs,
max.contrast for not, and
breakfast's candidate criterion for wbs2/tguh.
The values order the candidates within one result; they are not
comparable across engines, and the plot legend names the quantity
rather than calling all of them "Contrast".
For wbs2 and tguh the path is recomputed with
breakfast, because their fit objects do not keep the candidate
list. wbs2's search is randomised, so its path is a second
search of the same series rather than a record of the first: it can
differ between calls, and selected can be FALSE
throughout if the recomputed candidates miss the fit's own
changepoints. Every other engine's path is read off the fit.
cpt_statistic(), cpt_crops() for the
penalty path of an optimal-partitioning method.
set.seed(2026) fit <- cpt_detect(c(rnorm(150), rnorm(150, 3)), method = "binseg") cpt_solution_path(fit)set.seed(2026) fit <- cpt_detect(c(rnorm(150), rnorm(150, 3)), method = "binseg") cpt_solution_path(fit)
Most engines report a point set of changepoints with no measure of how
fragile it is. cpt_stability() fits the detector once, then
resamples residuals within the fitted segments (so the estimated
regime structure is preserved), re-runs the detector on each replicate,
and reports how often each location is re-detected. The resulting
detection-frequency profile is a cheap, model-agnostic confidence signal
available for every wrapped engine, including the many that ship no
confidence intervals.
cpt_stability( x, method = "pelt", B = 100, margin = 5, seed = NULL, bootstrap = c("iid", "block"), block_length = NULL, reversal = TRUE, ... ) ## S3 method for class 'ggcpt_stability' print(x, ...) ## S3 method for class 'ggcpt_stability' tidy(x, ...) ## S3 method for class 'ggcpt_stability' autoplot(object, ...)cpt_stability( x, method = "pelt", B = 100, margin = 5, seed = NULL, bootstrap = c("iid", "block"), block_length = NULL, reversal = TRUE, ... ) ## S3 method for class 'ggcpt_stability' print(x, ...) ## S3 method for class 'ggcpt_stability' tidy(x, ...) ## S3 method for class 'ggcpt_stability' autoplot(object, ...)
x |
A numeric vector, or a |
method |
Detection method, passed to |
B |
Number of bootstrap replicates. Defaults to |
margin |
Tolerance (in indices) when counting a replicate detection
as a re-detection of a location. Defaults to |
seed |
Optional seed for reproducibility. The seed is scoped to this
call: |
bootstrap |
|
block_length |
Block length for |
reversal |
Also run the detector once on the reversed series, and
flag each changepoint that the reversed series does not find within
|
... |
Additional arguments passed to every |
object |
A |
A ggcpt_stability object: a list with frequency
(a tibble of index and freq, the proportion of replicates
detecting a changepoint within margin of that index),
original (the point-estimate ggcpt), B,
n_failed (replicates on which the detector failed, which are
left out of the proportion rather than counted as "found nothing"),
bootstrap, block_length and reversal (one row per
original changepoint: cp and survives).
Methods: print(), tidy() (one row per original
changepoint: cp, stability and, when reversal ran,
survives_reversal) and autoplot() (frequency profile with
the original detections marked).
Reproducible under resampling, which is not the same as
real, and under dependent noise the two diverge: measured under
AR(1) noise, a spurious changepoint reached a stability of 1.00 and the
score separated real from spurious changepoints in only 4 of 10
replicates. The artifact is a feature of the realised noise path, and an
i.i.d. resample of the residuals rebuilds it every time.
bootstrap = "block" lets it vary; cpt_robustness(),
which changes the noise model rather than the sample, is the check that
touches the cause; and cpt_assumptions() tests the
residuals directly.
set.seed(2026) x <- c(rnorm(60), rnorm(60, 4)) st <- cpt_stability(x, method = "pelt", B = 20) st ggplot2::autoplot(st)set.seed(2026) x <- c(rnorm(60), rnorm(60, 4)) st <- cpt_stability(x, method = "pelt", B = 20) st ggplot2::autoplot(st)
Returns the criterion the engine evaluated at each position, which is what
explains why a changepoint landed where it did. Available for the
engines that expose it
(subset(cpt_methods(), statistic)$method lists them), and an error
naming those engines for the ones that do not.
cpt_statistic(object) ggcpt_statistic(object)cpt_statistic(object) ggcpt_statistic(object)
object |
A |
cpt_statistic() returns a tibble with index,
statistic, threshold (the engine's rejection threshold, or
NA) and label (what the statistic is).
ggcpt_statistic() returns a two-panel ggplot: the series above,
the statistic below, sharing the x axis.
cpt_solution_path(),
cpt_scale_space().
set.seed(2026) fit <- cpt_detect(c(rnorm(200), rnorm(200, 3)), method = "mosum") head(cpt_statistic(fit)) ggcpt_statistic(fit)set.seed(2026) fit <- cpt_detect(c(rnorm(200), rnorm(200, 3)), method = "mosum") head(cpt_statistic(fit)) ggcpt_statistic(fit)
Attaches a test to each detected changepoint (type = "jump") or to
each fitted segment (type = "segment"), using the engine's own
test where it has one and an explicitly unadjusted two-sample test
where it does not.
cpt_test( object, type = c("jump", "segment"), correction = "none", relevance = NULL )cpt_test( object, type = c("jump", "segment"), correction = "none", relevance = NULL )
object |
A |
type |
|
correction |
Multiple-testing correction applied across the rows, one
of the |
relevance |
Optional smallest change worth acting on, in noise
standard deviations. The null hypothesis becomes "the change is no
larger than |
A tibble with columns cp (or seg_id),
estimate, statistic, p_value, method and
selection_adjusted, plus cp_index on the original scale
when the result carries a time index (as cpt_confint()
does), and p_adjusted when correction is not
"none". estimate is the change in the segment mean
(the breakpoint's slope change for segmented), and NA
for a regression-mode strucchange fit, whose change is a vector
of coefficients; its Chow test is run on the full regression model.
A multivariate result is refused: both routes test one series.
read this before quoting a p-value:
Testing a changepoint at a location that was chosen because the data
looked like it changed there is circular, and the resulting p-values are
anti-conservative, often severely. The selection_adjusted column
records, per row, whether the test accounts for that:
TRUE for segmented's Davies test, which is built
for a nuisance parameter present only under the alternative. It is
one global test of "is there a breakpoint", not a test per
breakpoint, so on a multi-break fit every row carries the same
statistic and p-value, and the method string says so.
FALSE for the generic Welch two-sample fallback, which
compares the segments either side of the changepoint as if the
location had been fixed in advance. Useful as a descriptive effect
size with a scale attached; not a valid significance test for the
existence of the change. The exception is a changepoint that
was fixed in advance, through cpt_detect(fixed = ):
its row is TRUE.
The fallback compares means whatever the fit detected, so on a
fit of a change in variance, slope or distribution it tests a
different change from the one found, and warns (class
ggchangepoint_assumption).
FALSE for strucchange's route as well, which is
the Chow F evaluated at each estimated break date. The Chow
statistic's reference distribution assumes the date was fixed in
advance, so quoting it at a date the Bai-Perron dynamic program chose
is exactly the circularity this column exists to flag. Reporting
it is conventional in that literature, which does not make it
adjusted. The selection-adjusted objects there are the sup-type
statistics and the Bai-Perron critical values.
Two further limits worth knowing. type = "segment" is
always the unadjusted Welch test: the native routes above apply
only to type = "jump", so a segmented fit tested
per-segment does not use Davies' test. And the split above is by
engine and type, not by engine alone.
For a guarantee that survives selection, use nsp_wrapper()
(regions with exact global coverage) or cpt_confint() with
method = "nsp". The canonical post-detection tests of Jewell,
Fearnhead and Witten (2022) are implemented in ChangepointInference,
which is not on CRAN; cpt_register_method() is the supported
way to bring it in.
cpt_confint(), nsp_wrapper().
set.seed(2026) fit <- cpt_detect(c(rnorm(60), rnorm(60, 4)), method = "pelt") cpt_test(fit)set.seed(2026) fit <- cpt_detect(c(rnorm(60), rnorm(60, 4)), method = "pelt") cpt_test(fit)
The question behind most applied changepoint work: the policy took effect on 1 March, the plant was retooled in week 14, the drug was approved in Q2. Did anything change then? Because the date was chosen before looking at the data, this is an ordinary two-sample comparison at a fixed split and needs no adjustment for selection: the p-value means what it says.
cpt_test_at( x, when, window = 0, change_in = c("mean", "var", "meanvar", "distribution"), family = c("gaussian", "poisson", "binomial", "exponential", "l1"), span = NULL, index = NULL, data = NULL, level = 0.95, B = 999, seed = NULL ) ## S3 method for class 'ggcpt_test_at' print(x, ...) ## S3 method for class 'ggcpt_test_at' tidy(x, ...)cpt_test_at( x, when, window = 0, change_in = c("mean", "var", "meanvar", "distribution"), family = c("gaussian", "poisson", "binomial", "exponential", "l1"), span = NULL, index = NULL, data = NULL, level = 0.95, B = 999, seed = NULL ) ## S3 method for class 'ggcpt_test_at' print(x, ...) ## S3 method for class 'ggcpt_test_at' tidy(x, ...)
x |
A numeric series (a vector, |
when |
When the change took effect: the first observation
of the new regime, as a position or a value of the series' index (a
date; for a numeric index such as a |
window |
Allow the change anywhere within |
change_in |
What to test: |
family |
For |
span |
Optional number of observations each side of the split to compare. Defaults to all of them; a span keeps a change elsewhere in a long series out of the comparison. |
index |
Optional time index when |
data |
A data frame, for formula input. |
level |
Confidence level for the interval on the change. |
B |
Permutations for |
seed |
Optional seed for the permutations, scoped to this call. |
... |
Ignored. |
A ggcpt_test_at tibble with one row: when,
cp (the last observation before it, in the package's
convention) and cp_index, window, estimate (the
change: a difference in means, a ratio of rates or variances),
conf_low, conf_high, statistic, p_value,
n_before, n_after, method and
selection_adjusted (TRUE: the location was not chosen
from the data, and a window's search is paid for by the permutation).
cpt_attribute_event() for the mirror question
(was a detected change the event you know about?),
cpt_effect().
Other inference:
cpt_assumptions(),
cpt_attribute_event(),
cpt_effect(),
cpt_gof(),
cpt_null_power(),
cpt_robustness(),
cpt_test_null()
set.seed(1) dates <- as.Date("2026-01-01") + 0:119 x <- c(rnorm(60), rnorm(60, 0.8)) cpt_test_at(x, when = as.Date("2026-03-02"), index = dates) # the policy took effect sometime in that fortnight cpt_test_at(x, when = 61, window = 7, seed = 1)set.seed(1) dates <- as.Date("2026-01-01") + 0:119 x <- c(rnorm(60), rnorm(60, 0.8)) cpt_test_at(x, when = as.Date("2026-03-02"), index = dates) # the policy took effect sometime in that fortnight cpt_test_at(x, when = 61, window = 7, seed = 1)
A test of the global null hypothesis "the series has no changepoint", the question an empty detection raises. Nothing is located first, so nothing is selected, and the p-value means what it says.
cpt_test_null(x, method = c("cusum", "pettitt", "supF"), index = NULL)cpt_test_null(x, method = c("cusum", "pettitt", "supF"), index = NULL)
x |
A numeric series, or a |
method |
Which test:
|
index |
Optional time index for a bare series. |
A tibble with one row: method, statistic,
p_value, location (where the statistic peaks: the most
likely changepoint, reported for orientation only), n and
selection_adjusted (TRUE).
All three assume independent observations. Under positive
autocorrelation they reject too often, which is the same failure the
detectors share; see cpt_assumptions().
cpt_null_power() for what an empty answer could
have detected, cpt_test_at() for a pre-specified date.
Other inference:
cpt_assumptions(),
cpt_attribute_event(),
cpt_effect(),
cpt_gof(),
cpt_null_power(),
cpt_robustness(),
cpt_test_at()
set.seed(1) cpt_test_null(rnorm(200)) shifted <- c(rnorm(100), rnorm(100, 0.6)) cpt_test_null(shifted, method = "pettitt") cpt_test_null(shifted, method = "supF")set.seed(1) cpt_test_null(rnorm(200)) shifted <- c(rnorm(100), rnorm(100, 0.6)) cpt_test_null(shifted, method = "pettitt") cpt_test_null(shifted, method = "supF")
Pushes new data through a cpt_monitor(), updating its
internal state and appending to its alarm log. The monitor is returned, so
the idiom is mon <- cpt_update(mon, new_obs).
cpt_update(monitor, new_obs)cpt_update(monitor, new_obs)
monitor |
A |
new_obs |
New observations: a numeric vector, or a matrix with rows as time points for a multivariate monitor. |
The updated ggcpt_monitor: the same structure as the
input (see cpt_monitor()), with t advanced by
the number of new observations (rows, for a matrix) and any new rows
appended to alarms.
Re-assign it: the monitor is a value, not a mutable object, so
cpt_update(mon, y) without assignment discards the update.
cpt_monitor(), alarms().
set.seed(2026) mon <- cpt_monitor("edetector", baseline = rnorm(100)) mon <- cpt_update(mon, c(rnorm(50), rnorm(50, 3))) alarms(mon)set.seed(2026) mon <- cpt_monitor("edetector", baseline = rnorm(100)) mon <- cpt_update(mon, c(rnorm(50), rnorm(50, 3))) alarms(mon)
A result records which version of its engine produced it (see
glance()'s engine_version). cpt_verify() answers the
question that record exists for: does the answer still hold? It
re-runs the same method on the same series with the settings the result
recorded, using whatever engines are installed today, and reports whether
the changepoints moved and which versions changed in between.
cpt_verify(object, ..., tolerance = 0) ## S3 method for class 'ggcpt_verification' print(x, ...) ## S3 method for class 'ggcpt_verification' tidy(x, ...)cpt_verify(object, ..., tolerance = 0) ## S3 method for class 'ggcpt_verification' print(x, ...) ## S3 method for class 'ggcpt_verification' tidy(x, ...)
object |
A |
... |
Further arguments for the re-run, overriding what was recovered from the result (for instance an engine argument the recorded call held as a variable, which cannot be recovered from the object). |
tolerance |
Positions a changepoint may move and still count as
the same. Defaults to |
x |
A |
Upstream engines change: a default is revised, a bug is fixed, a tie-breaking rule moves. None of that raises an error, so a result produced last year and re-run today can differ without anything saying so. This is the check to run when re-opening an analysis, and before quoting an old result as current.
The re-run uses the series stored on the result, its method, the change
type it can be asked for, its penalty and family, the missing-value
handling and constraints it recorded (na_action, fixed,
within, min_segment, min_effect), and every engine
argument of the original call that was written as a literal (seed = 42,
n_intervals = 500). An argument written as a variable cannot be
recovered from the object, and is listed in not_recovered; pass
it again through ... if it mattered. A result read back with
cpt_import() from JSON keeps the call it was written with,
so it replays the same way; one made by anything but cpt_detect()
or a wrapper (as_ggcpt(), the fit
cpt_select() returns) is refused, since re-running
cpt_detect() would not reproduce how it was made.
A ggcpt_verification object: a list with verified
(TRUE when every changepoint reproduces within
tolerance), then and now (the two sets of
locations), added and removed (locations in one set with
no partner in the other), versions (a tibble with
component, then, now and changed),
not_recovered (call arguments that could not be replayed) and
refit, the new ggcpt. With a print() method.
glance.ggcpt() for the recorded
engine_version.
Other result class:
annotate_segments(),
as_cpt_series(),
as_ggcpt(),
as_json(),
cpt_annotations(),
cpt_export(),
ggchangepoint-conditions,
is_ggcpt(),
new_ggcpt(),
print.ggcpt()
set.seed(2026) fit <- cpt_detect(c(rnorm(80), rnorm(80, 4)), method = "pelt") cpt_verify(fit)set.seed(2026) fit <- cpt_detect(c(rnorm(80), rnorm(80, 4)), method = "pelt") cpt_verify(fit)
This function wraps a number of cpt functions from the changepoint
package and the cpt.np() function from the changepoint.np package.
It is handy that users can use this function to get the same changepoint
results as these functions output individually. Moreover, it returns a tibble
that inherits the tidyverse style. Functions from the changepoint package do
require data normality assumption by default, yet changepoint.np is a
non-parametric way to detect changepoints and let data speak by itself.
If user sets change_in as np (or cpt_np), a seed should
be set before using the function for the sake of reproducibility. For more
details on the changepoint and changepoint.np packages, please refer to
their documentation.
cpt_wrapper(data, change_in = "mean_var", cp_method = "PELT", ...)cpt_wrapper(data, change_in = "mean_var", cp_method = "PELT", ...)
data |
A numeric vector. |
change_in |
Choice of |
cp_method |
A wide range of choices (i.e., |
... |
Extra arguments for each |
A tibble including which point(s) is/are the changepoint along with
raw changepoint value corresponding to that changepoint. Changepoint
locations follow the convention of the changepoint package: the
last index of the left segment. The upstream cpt object is
attached as the "ggcpt_fit" attribute, which is what
cpt_detect() stores in the result's $fit.
With change_in = "mean" the upstream Normal cost assumes a noise
standard deviation of 1 and the penalty is compared against the raw
residual sum of squares, so a series with wider noise is under-penalised
and over-segmented: about 39 changepoints instead of 1 at
on 200 observations (mean over 20 draws). Standardise the series first, or use
change_in = "mean_var", which estimates a variance per segment and
is unaffected. See the scale-sensitivity section of
cpt_detect.
Killick R, Eckley I (2014). “changepoint: An R package for changepoint analysis.” Journal of statistical software, 58(3), 1–19.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2022) cpt_wrapper(c(rnorm(100,0,1),rnorm(100,0,10))) cpt_wrapper(c(rnorm(100,0,1),rnorm(100,10,1)))set.seed(2022) cpt_wrapper(c(rnorm(100,0,1),rnorm(100,0,10))) cpt_wrapper(c(rnorm(100,0,1),rnorm(100,10,1)))
Wraps DeCAFS::DeCAFS() (Romano, Rigaill, Runge and Fearnhead,
2022), which detects abrupt mean changes when the underlying signal also
drifts (random-walk fluctuations) and the noise is AR(1)-autocorrelated,
the two regimes in which plain change-in-mean methods over-detect. Model
parameters are estimated automatically unless supplied.
decafs_wrapper(x, penalty = NULL, model_param = NULL, ...)decafs_wrapper(x, penalty = NULL, model_param = NULL, ...)
x |
A numeric vector. |
penalty |
Penalty |
model_param |
Optional list of model parameters
( |
... |
Additional arguments passed to |
A ggcpt object. The data tibble carries the
estimated signal in its fitted column.
Romano G, Rigaill G, Runge V, Fearnhead P (2022). “Detecting abrupt changes in the presence of local fluctuations and autocorrelated noise.” Journal of the American Statistical Association, 117(540), 2147–2162.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) res <- decafs_wrapper(c(rnorm(100), rnorm(100, 5))) res$changepointsset.seed(2026) res <- decafs_wrapper(c(rnorm(100), rnorm(100, 5))) res$changepoints
The ecp package provides a non-parametric way to detect changepoints. Unlike
the changepoint package, it does not assume raw data to have any formal
distribution. This wrapper function wraps two functions from the ecp package,
i.e., e.divisive() and e.agglo(). Users can use either function
by switching the algorithm argument. Before using the wrapper function,
seed should be set for the sake of reproducibility.
ecp_wrapper(data, algorithm = "divisive", min_size = 2, seed = NULL, ...)ecp_wrapper(data, algorithm = "divisive", min_size = 2, seed = NULL, ...)
data |
A numeric vector (for univariate) or matrix/data.frame (for multivariate). |
algorithm |
Either |
min_size |
Minimum number of observations between change points. By
default is 2. This argument is only applied when |
seed |
Optional. A seed for reproducibility of the stochastic
permutation test. The seed is scoped to this call: |
... |
Extra arguments to pass on either from |
A tibble includes which point(s) is/are the changepoint along with
raw changepoint value corresponding to that changepoint. Changepoint
locations follow the ecp package convention: the first index of the
right segment. When no changepoint is found, an empty tibble is returned
(0 rows). The upstream fit is not retained ($fit is
NULL on a ggcpt from cpt_detect(method = "ecp")),
because ecp::e.agglo()'s cluster-progression matrix is quadratic
in the series length; call the ecp functions directly if you need
their full output.
James NA, Matteson DS (2014). “ecp: An R package for nonparametric multiple change point analysis of multivariate data.” Journal of Statistical Software, 62(7), 1–25. doi:10.18637/jss.v062.i07.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2022) ecp_wrapper(c(rnorm(100,0,1),rnorm(100,0,10))) ecp_wrapper(c(rnorm(100,0,1),rnorm(100,10,1)))set.seed(2022) ecp_wrapper(c(rnorm(100,0,1),rnorm(100,0,10))) ecp_wrapper(c(rnorm(100,0,1),rnorm(100,10,1)))
Wraps EnvCpt::envcpt() (Beaulieu and Killick, 2018), which fits up
to twelve competing models (constant mean or linear trend, each with or
without changepoints, and with white-noise, AR(1) or AR(2) errors) and
lets an information criterion decide whether the series really contains
changepoints or merely trend/autocorrelation ("memory"). The changepoints
of the winning model (if any) are returned, and the winning model's name
is recorded, guarding against the classic false positive of running a
mean-shift detector on autocorrelated data.
envcpt_wrapper( x, models = c("mean", "meancpt", "meanar1", "meanar2", "meanar1cpt", "meanar2cpt", "trend", "trendcpt", "trendar1", "trendar2", "trendar1cpt", "trendar2cpt"), criterion = c("AIC", "BIC"), minseglen = 5, ... )envcpt_wrapper( x, models = c("mean", "meancpt", "meanar1", "meanar2", "meanar1cpt", "meanar2cpt", "trend", "trendcpt", "trendar1", "trendar2", "trendar1cpt", "trendar2cpt"), criterion = c("AIC", "BIC"), minseglen = 5, ... )
x |
A numeric vector. |
models |
Character vector of models to fit; see
|
criterion |
Model selection criterion: |
minseglen |
Minimum segment length. Defaults to |
... |
Additional arguments passed to |
A ggcpt object. $fit holds the full envcpt
output; the selected model name is stored in the penalty descriptor and
printed by glance() via penalty_type. Individual model
fits that fail are expected (the criterion ignores them), so the
engine's own try() output is not passed on; genuine warnings
still are, and a series on which no model fits at all raises an error.
A constant series has no changepoints and is not handed to the engine,
so $fit is NULL there.
Beaulieu C, Killick R (2018). “Distinguishing trends and shifts from memory in climate data.” Journal of Climate, 31(23), 9519–9543.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) res <- envcpt_wrapper(c(rnorm(100), rnorm(100, 3))) res$changepointsset.seed(2026) res <- envcpt_wrapper(c(rnorm(100), rnorm(100, 3))) res$changepoints
Wraps HDCD::ESAC() (Moen, Glad and Tveten, 2023): Efficient
Sparsity Adaptive Changepoint estimation for a change in the mean vector
of a high-dimensional series. Where inspect projects onto a single
estimated sparse direction, ESAC adapts across the whole sparsity range at
once, which is a different regime rather than a refinement of the same one:
it is competitive both when a handful of coordinates change and when all
of them do.
esac_wrapper( x, threshold_d = 1.5, threshold_s = 1, empirical = FALSE, N = 1000, seed = NULL, ... )esac_wrapper( x, threshold_d = 1.5, threshold_s = 1, empirical = FALSE, N = 1000, seed = NULL, ... )
x |
A numeric matrix or data frame with rows as time points and columns as coordinates. |
threshold_d, threshold_s
|
Leading constants of the dense and sparse
thresholds. Defaults follow the engine ( |
empirical |
Calibrate the thresholds by Monte Carlo rather than using
the theoretical values? Slower but sharper; defaults to |
N |
Monte Carlo samples when |
seed |
Optional seed (used by the empirical calibration). The seed
is scoped to this call: |
... |
Additional arguments passed to |
A ggcpt object. The changepoints tibble carries
cusum (the ESAC statistic at each detected location) and
depth (its level in the recursion).
Moen PAJ, Glad IK, Tveten M (2024). “Efficient sparsity adaptive changepoint estimation.” Electronic Journal of Statistics, 18(2), 3975–4038. doi:10.1214/24-EJS2294.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) X <- matrix(rnorm(100 * 20), nrow = 100) X[51:100, 1:5] <- X[51:100, 1:5] + 3 esac_wrapper(X)set.seed(2026) X <- matrix(rnorm(100 * 20), nrow = 100) X[51:100, 1:5] <- X[51:100, 1:5] + 3 esac_wrapper(X)
Wraps fabisearch::detect.cps() (Ondrus, Olds and Cribben, 2024):
factorised binary search for changes in the network structure of a
high-dimensional series. Each candidate split is scored by how much better
a rank- non-negative matrix factorisation fits the two halves
separately than together, and significance is assessed by permutation.
fabisearch_wrapper( x, min_dist = 35, n_runs = 50, n_reps = 100, alpha = NULL, rank = NULL, n_core = 1, seed = NULL, ... )fabisearch_wrapper( x, min_dist = 35, n_runs = 50, n_reps = 100, alpha = NULL, rank = NULL, n_core = 1, seed = NULL, ... )
x |
A non-negative numeric matrix or data frame with rows as time points and columns as nodes. Non-negativity is a hard requirement of NMF, not a preference; see the section below. |
min_dist |
Minimum distance between changepoints. Defaults to
|
n_runs |
NMF runs per candidate split. Defaults to |
n_reps |
Replicates on each side of the significance test: the
split is refitted |
alpha |
Significance level applied to the p-value each candidate
split receives. Defaults to |
rank |
NMF rank, a positive whole number. |
n_core |
Cores for the permutation stage. Defaults to |
seed |
Optional seed. The seed is scoped to this call:
|
... |
Additional arguments passed to |
A ggcpt object with change_in = "network". Multivariate input is
reduced to one series per observation by taking the
cross-sectional mean of the columns, and that is the series stored on
the result: autoplot() draws it, tidy()'s
cp_value reads it, and $segments$param_estimate and
augment()'s .fitted/.resid are computed from it.
It is not any one column of the input. The full input is kept in
$data_wide for autoplot(type = "coordinates").
Three practical notes. (1) NMF is undefined for negative entries, so this
wrapper refuses them rather than letting the engine fail deep inside a
factorisation; shift or rescale the series first if it has negatives.
(2) It is by far the most expensive engine here (n_runs times
n_reps factorisations per candidate split), so the defaults are
lowered in the examples. The engine's own progress output is suppressed,
so a long call is silent until it returns. (3) fabisearch calls
NMF's multi-run machinery, which resolves helpers through the
search path and fails with "none of the packages are loaded" when
NMF is merely loaded; this wrapper therefore attaches NMF for
the duration of the call and detaches it again afterwards.
Ondrus M, Cribben I (2024). “fabisearch: a package for change point detection in and visualization of the network structure of multivariate high-dimensional time series in R.” Neurocomputing, 578, 127321. doi:10.1016/j.neucom.2024.127321.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
# A change in *structure*, not in scale: two latent factors drive # different halves of the node set before and after the change. # Deliberately tiny: this is by far the most expensive engine in the # package (n_runs x n_reps factorisations per candidate split). Measured # at 5-6 s across fresh sessions, against 27 s for the 2 x 25 / # n_reps = 4 # version this replaced, and this is the floor: `n_reps = 1` fails # inside fabisearch with "not enough 'x' observations" (the permutation # test needs two), and smaller matrices are not reliably cheaper because # the search then evaluates more splits relative to `min_dist` (2 x 10 at # min_dist = 8 measured 6.6 s). So this one example stays near CRAN's 5 s # budget by necessity; `cran-comments.md` says so. Use the defaults on # real data; the settings here are for the budget, not for detection. set.seed(2026) block <- function(n, cols) { f <- abs(stats::rnorm(n)) + 0.5 Y <- matrix(abs(stats::rnorm(n * 5)) * 0.2 + 0.1, n, 5) Y[, cols] <- Y[, cols] + f Y } Y <- rbind(block(12, 1:2), block(12, 3:5)) fabisearch_wrapper(Y, min_dist = 10, n_runs = 1, n_reps = 2, alpha = 0.25, rank = 2)# A change in *structure*, not in scale: two latent factors drive # different halves of the node set before and after the change. # Deliberately tiny: this is by far the most expensive engine in the # package (n_runs x n_reps factorisations per candidate split). Measured # at 5-6 s across fresh sessions, against 27 s for the 2 x 25 / # n_reps = 4 # version this replaced, and this is the floor: `n_reps = 1` fails # inside fabisearch with "not enough 'x' observations" (the permutation # test needs two), and smaller matrices are not reliably cheaper because # the search then evaluates more splits relative to `min_dist` (2 x 10 at # min_dist = 8 measured 6.6 s). So this one example stays near CRAN's 5 s # budget by necessity; `cran-comments.md` says so. Use the defaults on # real data; the settings here are for the budget, not for detection. set.seed(2026) block <- function(n, cols) { f <- abs(stats::rnorm(n)) + 0.5 Y <- matrix(abs(stats::rnorm(n * 5)) * 0.2 + 0.1, n, 5) Y[, cols] <- Y[, cols] + f Y } Y <- rbind(block(12, 1:2), block(12, 3:5)) fabisearch_wrapper(Y, min_dist = 10, n_runs = 1, n_reps = 2, alpha = 0.25, rank = 2)
Wraps the fastcpd package (Li and Zhang, 2024), a modern PELT-family
engine that pairs pruning with sequential gradient descent so that exact or
near-exact segmentations of many model families run in near-linear time.
Every family the engine documents is reachable except its user-supplied
custom cost: Gaussian mean, variance and both; the count and
binary families ("poisson", "binomial") and waiting times
("exponential"); linear and penalised regression ("lm",
"lasso") and generalised linear models ("poisson",
"binomial" with covariates); and the time-series models
"ar", "arma", "arima", "garch" and, for a
multivariate series, "var".
fastcpd_wrapper( x, family = c("mean", "variance", "meanvariance", "ar", "arma", "arima", "garch", "var", "lm", "lasso", "poisson", "binomial", "exponential"), order = NULL, covariates = NULL, ... )fastcpd_wrapper( x, family = c("mean", "variance", "meanvariance", "ar", "arma", "arima", "garch", "var", "lm", "lasso", "poisson", "binomial", "exponential"), order = NULL, covariates = NULL, ... )
x |
A numeric vector, or (for |
family |
Model family. |
order |
Model order for |
covariates |
Optional numeric matrix of regressors, one row per
observation, for |
... |
Additional arguments passed to the corresponding
|
A ggcpt object. The engine's per-segment parameter
estimates (thetas) are kept as $coefficients, one row
per segment and parameter, for the families where they are
coefficients (the regressions and the intercept-only count, binary and
waiting-time models).
Li X, Zhang X (2024). “fastcpd: Fast change point detection in R.” arXiv preprint arXiv:2404.05933.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) res <- fastcpd_wrapper(c(rnorm(100), rnorm(100, 4))) res$changepoints # A change in a Poisson rate counts <- fastcpd_wrapper(c(rpois(100, 3), rpois(100, 9)), family = "poisson") counts$changepointsset.seed(2026) res <- fastcpd_wrapper(c(rnorm(100), rnorm(100, 4))) res$changepoints # A change in a Poisson rate counts <- fastcpd_wrapper(c(rpois(100, 3), rpois(100, 9)), family = "poisson") counts$changepoints
Wraps fChange::fchange() for changes in the covariance operator,
eigenstructure or trace of a functional time series: the changes that
leave the mean curve untouched.
fcov_wrapper( x, target = c("covariance", "trace", "eigenjoint", "eigensingle"), statistic = c("Tn", "Mn"), critical = c("simulation", "resample", "welch"), type = c("segmentation", "single"), alpha = 0.05, ... )fcov_wrapper( x, target = c("covariance", "trace", "eigenjoint", "eigensingle"), statistic = c("Tn", "Mn"), critical = c("simulation", "resample", "welch"), type = c("segmentation", "single"), alpha = 0.05, ... )
x |
A numeric matrix or data frame with one row per time point and one column per grid location (the curve's resolution). |
target |
What to test: |
statistic |
Test statistic: |
critical |
How critical values are obtained: |
type |
|
alpha |
Significance level. Defaults to |
... |
Additional arguments passed to |
A ggcpt object with change_in = "covariance". Multivariate input is
reduced to one series per observation by taking the
cross-sectional mean of the columns, and that is the series stored on
the result: autoplot() draws it, tidy()'s
cp_value reads it, and $segments$param_estimate and
augment()'s .fitted/.resid are computed from it.
It is not any one column of the input. The full input is kept in
$data_wide for autoplot(type = "coordinates").
For a covariance change this matters when reading the plot: a change in
the covariance structure need not move the cross-sectional mean at all,
so autoplot() can legitimately show changepoint rules on a
series with no visible change in it. That is the detector working, not
misfiring; use autoplot(type = "coordinates") to see the
columns the change is in.
Minutes, not seconds, on a series of a hundred points: by a
wide margin the most expensive engine in the package, and slow enough
that a first call looks like a hung session. Timed on one Linux x86-64
machine, against fmean_wrapper() on the identical input
so the comparison is the same package and the same data:
| input | fmean | fcov |
, |
4.5 s | 316 s |
, |
2.9 s | 598 s |
The cost is roughly linear in the number of time points and it is in the
engine's own estimation rather than in this wrapper. It is, however,
dominated by target, which the rest of this section used to deny.
Measured at , , M = 50 on one Linux
x86-64 machine:
| target | time | changepoints found |
"covariance" (default) |
477 s | none |
"eigenjoint" |
21.7 s | none |
"eigensingle" |
21.7 s | none |
"trace" |
2.1 s | 16, 30, 38 |
So the default is some two hundred times the cost of "trace", and
the example below uses "trace" for that reason. Read that as a
choice of test and not as a free speedup: the trace is a scalar summary
of the covariance operator, so it is a weaker instrument that happens to
be cheap, and the row above is one series rather than a comparison of
power. If a covariance change matters and the full operator test is the
one you want, budget for it.
Two practical consequences either way: size the call before starting it,
and do not put the default in a loop: a twelve-replicate study at
is two hours. Another machine will give different
absolute numbers; the ratios are the part to plan around.
The “Benchmarks” article compares the engines that do scale.
Aue A, Rice G, Sönmez O (2020). “Structural break analysis for spectrum and trace of covariance operators.” Environmetrics, 31(1), e2617.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) # See the note in ?fmean_wrapper on why this is 10 curves and M = 50. X <- matrix(rnorm(60 * 10), nrow = 60) X[31:60, ] <- X[31:60, ] * 3 fcov_wrapper(X, target = "trace", M = 50)set.seed(2026) # See the note in ?fmean_wrapper on why this is 10 curves and M = 50. X <- matrix(rnorm(60 * 10), nrow = 60) X[31:60, ] <- X[31:60, ] * 3 fcov_wrapper(X, target = "trace", M = 50)
Wraps fChange::fchange() for changes in the mean function of
a functional time series: each observation is a curve, and the question is
when the average curve shape changes. The binary-segmentation
("segmentation") mode finds multiple changes; the "single"
mode runs the one-change test and reports its p-value.
fmean_wrapper( x, statistic = c("Tn", "Mn"), critical = c("simulation", "resample", "welch"), type = c("segmentation", "single"), alpha = 0.05, robust = FALSE, ... )fmean_wrapper( x, statistic = c("Tn", "Mn"), critical = c("simulation", "resample", "welch"), type = c("segmentation", "single"), alpha = 0.05, robust = FALSE, ... )
x |
A numeric matrix or data frame with one row per time point and one column per grid location (the curve's resolution). |
statistic |
Test statistic: |
critical |
How critical values are obtained: |
type |
|
alpha |
Significance level. Defaults to |
robust |
Use the robust ( |
... |
Additional arguments passed to |
A ggcpt object; the changepoints tibble carries the
engine's p_value for each location. Multivariate input is
reduced to one series per observation by taking the
cross-sectional mean of the columns, and that is the series stored on
the result: autoplot() draws it, tidy()'s
cp_value reads it, and $segments$param_estimate and
augment()'s .fitted/.resid are computed from it.
It is not any one column of the input. The full input is kept in
$data_wide for autoplot(type = "coordinates").
Aue A, Rice G, Sönmez O (2018). “Detecting and dating structural breaks in functional data without dimension reduction.” Journal of the Royal Statistical Society: Series B, 80(3), 509–529. doi:10.1111/rssb.12257.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) # 10 curves and M = 50, not 20 and 200: the example is a demonstration, # and the wider version measured 6.7 s against CRAN's 5 s budget. X <- matrix(rnorm(60 * 10), nrow = 60) X[31:60, ] <- X[31:60, ] + 2 fmean_wrapper(X, M = 50)set.seed(2026) # 10 curves and M = 50, not 20 and 200: the example is a demonstration, # and the wider version measured 6.7 s against CRAN's 5 s budget. X <- matrix(rnorm(60 * 10), nrow = 60) X[31:60, ] <- X[31:60, ] + 2 fmean_wrapper(X, M = 50)
Wraps the fpop package for optimal changepoint detection via
functional pruning.
fpop_wrapper(x, penalty = NULL, ...)fpop_wrapper(x, penalty = NULL, ...)
x |
A numeric vector. |
penalty |
Penalty value. Defaults to |
... |
Additional arguments passed to |
fpop was archived from CRAN in 2026 at its maintainer's request and
is still built on R-Forge, where it is developed. Install it with
install.packages("fpop", repos = "https://R-Forge.R-project.org"),
or with cpt_install_engines("core").
A ggcpt object.
Maidstone R, Hocking T, Rigaill G, Fearnhead P (2017). “On Optimal Multiple Changepoint Algorithms for Large Data.” Statistics and Computing, 27(2), 519–533. doi:10.1007/s11222-016-9636-3.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) x <- c(rnorm(60), rnorm(60, 4)) fpop_wrapper(x)$changepoints # the default penalty assumes sd 1; scale it for wider noise y <- 5 * x fpop_wrapper(y, penalty = log(length(y)) * var(diff(y)))$changepointsset.seed(2026) x <- c(rnorm(60), rnorm(60, 4)) fpop_wrapper(x)$changepoints # the default penalty assumes sd 1; scale it for wider noise y <- 5 * x fpop_wrapper(y, penalty = log(length(y)) * var(diff(y)))$changepoints
Draws vertical lines at changepoint locations. Mimics geom_vline
but designed to work with the tidy changepoint data frames returned by
the package. Can be used as a standalone layer:
geom_changepoint(data = cp_df, aes(xintercept = cp)).
geom_changepoint( mapping = NULL, data = NULL, ..., na.rm = FALSE, show.legend = NA )geom_changepoint( mapping = NULL, data = NULL, ..., na.rm = FALSE, show.legend = NA )
mapping |
Set of aesthetic mappings created by |
data |
A data frame with changepoint information. |
... |
Other arguments passed to |
na.rm |
If |
show.legend |
Whether to show legend. |
A ggplot layer.
Other ggplot2 layers:
geom_cpt_ci(),
geom_cpt_event(),
geom_cpt_label(),
geom_cpt_region(),
geom_cpt_segment(),
ggchangepoint-ggproto,
stat_changepoint(),
stat_cpt_region()
library(ggplot2) set.seed(2026) d <- data.frame(t = 1:100, y = c(rnorm(50), rnorm(50, 4))) cp <- data.frame(cp = cpt_detect(d$y, method = "pelt")$changepoints$cp) ggplot(d, aes(t, y)) + geom_line() + geom_changepoint(aes(xintercept = cp), data = cp, colour = "blue")library(ggplot2) set.seed(2026) d <- data.frame(t = 1:100, y = c(rnorm(50), rnorm(50, 4))) cp <- data.frame(cp = cpt_detect(d$y, method = "pelt")$changepoints$cp) ggplot(d, aes(t, y)) + geom_line() + geom_changepoint(aes(xintercept = cp), data = cp, colour = "blue")
Draws horizontal whiskers for changepoint-location confidence intervals (e.g. from MOSUM, stepR, strucchange, segmented).
geom_cpt_ci(mapping = NULL, data = NULL, ..., na.rm = FALSE, show.legend = NA)geom_cpt_ci(mapping = NULL, data = NULL, ..., na.rm = FALSE, show.legend = NA)
mapping |
Aesthetic mappings. Requires |
data |
A data frame with CI information. |
... |
Other arguments passed to |
na.rm |
If |
show.legend |
Whether to show legend. |
A ggplot layer.
Other ggplot2 layers:
geom_changepoint(),
geom_cpt_event(),
geom_cpt_label(),
geom_cpt_region(),
geom_cpt_segment(),
ggchangepoint-ggproto,
stat_changepoint(),
stat_cpt_region()
library(ggplot2) set.seed(2026) d <- data.frame(t = 1:100, y = c(rnorm(50), rnorm(50, 4))) ci <- data.frame(xmin = 45, xmax = 56, y = 0) ggplot(d, aes(t, y)) + geom_line() + geom_cpt_ci(aes(xmin = xmin, xmax = xmax, y = y), data = ci, inherit.aes = FALSE, width = 0.4, colour = "blue")library(ggplot2) set.seed(2026) d <- data.frame(t = 1:100, y = c(rnorm(50), rnorm(50, 4))) ci <- data.frame(xmin = 45, xmax = 56, y = 0) ggplot(d, aes(t, y)) + geom_line() + geom_cpt_ci(aes(xmin = xmin, xmax = xmax, y = y), data = ci, inherit.aes = FALSE, width = 0.4, colour = "blue")
Marks known real-world events on a changepoint plot: a vertical rule plus
a text label. "Changepoint at index 147" is not a finding; "changepoint at
2020-03-11, matching the WHO pandemic declaration" is.
cpt_annotate_events() produces the frame this layer expects
and, crucially, also reports the changepoints no event explains and the
events no changepoint found.
geom_cpt_event( mapping = NULL, data = NULL, ..., colour = "grey30", linetype = "dotted", angle = 90, size = 3, vjust = -0.4, hjust = 0, repel = NULL, inherit.aes = FALSE, na.rm = FALSE )geom_cpt_event( mapping = NULL, data = NULL, ..., colour = "grey30", linetype = "dotted", angle = 90, size = 3, vjust = -0.4, hjust = 0, repel = NULL, inherit.aes = FALSE, na.rm = FALSE )
mapping |
Aesthetic mappings. Requires |
data |
A data frame of events (see
|
... |
Other arguments passed to the text layer. |
colour |
Rule and text colour. Defaults to |
linetype |
Rule linetype. Defaults to |
angle |
Text angle in degrees. Defaults to |
size |
Text size. Defaults to |
vjust, hjust
|
Text justification. |
repel |
Use ggrepel to keep labels from overlapping? Defaults
to |
inherit.aes |
Whether the label layer inherits the plot's
aesthetics. Defaults to |
na.rm |
If |
A list of two ggplot layers (a rule and a label), which can be added to a plot exactly like a single layer.
Other ggplot2 layers:
geom_changepoint(),
geom_cpt_ci(),
geom_cpt_label(),
geom_cpt_region(),
geom_cpt_segment(),
ggchangepoint-ggproto,
stat_changepoint(),
stat_cpt_region()
library(ggplot2) set.seed(2026) d <- data.frame(t = 1:100, y = c(rnorm(50), rnorm(50, 4))) ev <- data.frame(x = 50, label = "policy change") ggplot(d, aes(t, y)) + geom_line() + geom_cpt_event(aes(xintercept = x, label = label), data = ev, repel = FALSE)library(ggplot2) set.seed(2026) d <- data.frame(t = 1:100, y = c(rnorm(50), rnorm(50, 4))) ev <- data.frame(x = 50, label = "policy change") ggplot(d, aes(t, y)) + geom_line() + geom_cpt_event(aes(xintercept = x, label = label), data = ev, repel = FALSE)
Draws labelled regions behind a series: the central object of supervised
changepoint detection (Hocking et al.), where an expert marks intervals as
containing a change or not and the penalty is learned from those labels.
Fill defaults to the label's change status, so a plot of labels
reads as a picture of what the expert asserted; map fill to the
status column of cpt_label_error() instead to get the
correct / false-positive / false-negative display.
geom_cpt_label( mapping = NULL, data = NULL, ..., alpha = 0.25, colour = NA, na.rm = FALSE, show.legend = NA, inherit.aes = FALSE )geom_cpt_label( mapping = NULL, data = NULL, ..., alpha = 0.25, colour = NA, na.rm = FALSE, show.legend = NA, inherit.aes = FALSE )
mapping |
Aesthetic mappings. Requires |
data |
A data frame of labels, e.g. |
... |
Other arguments passed to |
alpha |
Fill transparency. Defaults to |
colour |
Border colour. Defaults to |
na.rm |
If |
show.legend |
Whether to show a legend. |
inherit.aes |
Whether to inherit the plot's aesthetics. Defaults to
|
A ggplot layer.
cpt_labels(), cpt_label_error(),
scale_fill_cpt_label().
Other ggplot2 layers:
geom_changepoint(),
geom_cpt_ci(),
geom_cpt_event(),
geom_cpt_region(),
geom_cpt_segment(),
ggchangepoint-ggproto,
stat_changepoint(),
stat_cpt_region()
library(ggplot2) set.seed(2026) d <- data.frame(t = 1:100, y = c(rnorm(50), rnorm(50, 4))) labs <- cpt_labels(c(40, 70), c(60, 90), c("change", "no_change")) ggplot(d, aes(t, y)) + geom_cpt_label(aes(xmin = start, xmax = end, fill = change), data = labs) + geom_line() + scale_fill_cpt_label()library(ggplot2) set.seed(2026) d <- data.frame(t = 1:100, y = c(rnorm(50), rnorm(50, 4))) labs <- cpt_labels(c(40, 70), c(60, 90), c("change", "no_change")) ggplot(d, aes(t, y)) + geom_cpt_label(aes(xmin = start, xmax = end, fill = change), data = labs) + geom_line() + scale_fill_cpt_label()
Draws a changepoint that is an interval: a vertical band spanning
xmin to xmax and the full height of the panel. This is the
display Narrowest Significance Pursuit needs
(nsp_wrapper()): NSP returns intervals each of which
contains at least one changepoint at a prescribed global
significance level, which is neither a point estimate nor a confidence
interval around one. autoplot() adds this layer automatically for
a result that carries regions.
geom_cpt_region( mapping = NULL, data = NULL, ..., alpha = 0.2, fill = "steelblue", na.rm = FALSE, show.legend = NA, inherit.aes = FALSE )geom_cpt_region( mapping = NULL, data = NULL, ..., alpha = 0.2, fill = "steelblue", na.rm = FALSE, show.legend = NA, inherit.aes = FALSE )
mapping |
Aesthetic mappings. Requires |
data |
A data frame of regions, e.g. |
... |
Other arguments passed to |
alpha |
Fill transparency. Defaults to |
fill |
Band fill colour. Defaults to |
na.rm |
If |
show.legend |
Whether to show a legend. |
inherit.aes |
Whether to inherit the plot's aesthetics. Defaults to
|
A ggplot layer.
nsp_wrapper(), cpt_regions().
Other ggplot2 layers:
geom_changepoint(),
geom_cpt_ci(),
geom_cpt_event(),
geom_cpt_label(),
geom_cpt_segment(),
ggchangepoint-ggproto,
stat_changepoint(),
stat_cpt_region()
library(ggplot2) set.seed(2026) d <- data.frame(t = 1:100, y = c(rnorm(50), rnorm(50, 4))) regions <- data.frame(xmin = 44, xmax = 57) ggplot(d, aes(t, y)) + geom_cpt_region(aes(xmin = xmin, xmax = xmax), data = regions) + geom_line()library(ggplot2) set.seed(2026) d <- data.frame(t = 1:100, y = c(rnorm(50), rnorm(50, 4))) regions <- data.frame(xmin = 44, xmax = 57) ggplot(d, aes(t, y)) + geom_cpt_region(aes(xmin = xmin, xmax = xmax), data = regions) + geom_line()
Draws horizontal segments representing the estimated level of each segment
between changepoints. Typically used with data from augment().
geom_cpt_segment( mapping = NULL, data = NULL, ..., na.rm = FALSE, show.legend = NA )geom_cpt_segment( mapping = NULL, data = NULL, ..., na.rm = FALSE, show.legend = NA )
mapping |
Aesthetic mappings. Requires |
data |
A data frame with segment information. |
... |
Other arguments passed to |
na.rm |
If |
show.legend |
Whether to show legend. |
A ggplot layer.
Other ggplot2 layers:
geom_changepoint(),
geom_cpt_ci(),
geom_cpt_event(),
geom_cpt_label(),
geom_cpt_region(),
ggchangepoint-ggproto,
stat_changepoint(),
stat_cpt_region()
library(ggplot2) set.seed(2026) fit <- cpt_detect(c(rnorm(50), rnorm(50, 4)), method = "pelt") ggplot(fit$data, aes(index, value)) + geom_line(colour = "grey70") + geom_cpt_segment(aes(x = start, xend = end, y = param_estimate, yend = param_estimate), data = fit$segments, colour = "blue", linewidth = 1)library(ggplot2) set.seed(2026) fit <- cpt_detect(c(rnorm(50), rnorm(50, 4)), method = "pelt") ggplot(fit$data, aes(index, value)) + geom_line(colour = "grey70") + geom_cpt_segment(aes(x = start, xend = end, y = param_estimate, yend = param_estimate), data = fit$segments, colour = "blue", linewidth = 1)
Wraps changepoint.geo::geomcp() (Grundy, Killick and Mihaylov,
2020): each multivariate observation is mapped to its distance from, and
angle to, a reference point, and univariate PELT is run on the two mapped
series. Distance changes capture shifts in magnitude, angle changes
capture shifts in orientation/correlation structure.
geomcp_wrapper( x, penalty = "MBIC", mapping = c("both", "distance", "angle"), ... )geomcp_wrapper( x, penalty = "MBIC", mapping = c("both", "distance", "angle"), ... )
x |
A numeric matrix or data frame with one row per time point. |
penalty |
Penalty for the univariate PELT runs (a
changepoint-style character penalty). Defaults to |
mapping |
Which mapped series' changepoints to report:
|
... |
Additional arguments passed to
|
A ggcpt object whose changepoints tibble carries a
mapping column ("distance" or "angle"; a location
found in both is labelled "both").
Grundy T, Killick R, Mihaylov G (2020). “High-dimensional changepoint detection via a geometrically inspired mapping.” Statistics and Computing, 30, 1155–1166.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) X <- rbind(matrix(rnorm(100 * 4), 100), matrix(rnorm(100 * 4, 2), 100)) res <- geomcp_wrapper(X) res$changepointsset.seed(2026) X <- rbind(matrix(rnorm(100 * 4), 100), matrix(rnorm(100 * 4, 2), 100)) res <- geomcp_wrapper(X) res$changepoints
Every error, warning and message this package raises carries a class, so code that calls it can react to the kind of failure rather than matching its wording. The text is written for a person and may be improved between releases; the classes and the fields listed here are the interface, and follow the package's deprecation policy.
Every error inherits from ggchangepoint_error (and from
error and condition). The subclasses, most specific first:
ggchangepoint_input_errorThe call itself is not usable:
a bad argument or data that violates a precondition. Its subclasses
say which precondition:
ggchangepoint_short_series (too few observations, for the
package or for the engine that was asked; field n),
ggchangepoint_wrong_dimension (a univariate method handed a
matrix, or the reverse),
ggchangepoint_non_finite (NA, NaN or Inf
where the method needs finite data),
ggchangepoint_bad_type (a factor, text, a survival object or
timestamps where a numeric series was expected) and
ggchangepoint_bad_argument (an argument value outside its
documented range or vocabulary).
ggchangepoint_unsupportedThe request is well formed but
not something this method offers: a change_in, family
or capability the registry does not list for it. Fields
method, requested and supported where they
apply. Subclasses: ggchangepoint_capability_absent (the
result carries no interval, statistic, path or posterior to read),
ggchangepoint_planned_method (named in cpt_methods()
but not wired) and ggchangepoint_unknown_method.
ggchangepoint_engine_missingA suggested engine package
is not installed. Field package, and install, the call
that installs it.
ggchangepoint_engine_errorThe upstream engine failed.
Fields engine, method and, where it was caught,
parent, the engine's own condition.
ggchangepoint_upstream_bugA known, version-guarded
defect in an engine, refused rather than returned. Fields
package and version.
ggchangepoint_internal_errorA state the package should never reach: a bug here, worth reporting.
The functions that run many fits (cpt_benchmark(),
cpt_consensus()) record a failure that belongs to one
method (ggchangepoint_engine_error,
ggchangepoint_engine_missing, ggchangepoint_unsupported,
ggchangepoint_upstream_bug, or a series of the wrong shape or
length for that method) and carry on; any other error stops them, since
every method would have hit it.
Every warning inherits from ggchangepoint_warning. The ones worth
handling by class: ggchangepoint_assumption and its subclasses
ggchangepoint_scale_sensitive, ggchangepoint_data_type and
ggchangepoint_dependence (the method's assumptions look violated
for this series); ggchangepoint_degenerate_segmentation (a
changepoint after every observation); ggchangepoint_implausible_count
(more changepoints than the series can plausibly hold);
ggchangepoint_change_in_routed (the request was answered with the
method's native change type); ggchangepoint_argument_ignored;
ggchangepoint_level_not_applied; ggchangepoint_selection_unadjusted
(p-values computed at data-chosen locations);
ggchangepoint_collapsed_ladder; ggchangepoint_replicates_failed;
ggchangepoint_cp_dropped (locations normalised away by
as_ggcpt()); ggchangepoint_irregular_index;
ggchangepoint_na_omitted; ggchangepoint_wide_interval;
ggchangepoint_large_fit; ggchangepoint_short_series_warning
(a series too short for the result to be interpretable);
ggchangepoint_dropped_input (constant coordinates or out-of-range
locations left out); ggchangepoint_engine_failed (some methods
failed and were left out); ggchangepoint_recycled_input;
ggchangepoint_constraint and ggchangepoint_deprecated.
Anything else is plain ggchangepoint_warning.
Informational messages inherit from ggchangepoint_message, so
suppressMessages(classes = "ggchangepoint_message") silences this
package without silencing the engines.
Other result class:
annotate_segments(),
as_cpt_series(),
as_ggcpt(),
as_json(),
cpt_annotations(),
cpt_export(),
cpt_verify(),
is_ggcpt(),
new_ggcpt(),
print.ggcpt()
res <- tryCatch(cpt_detect(c(1, 2), method = "pelt"), ggchangepoint_short_series = function(e) "too short") res # Branch on the kind of failure, not on its wording: tryCatch( cpt_detect(rnorm(50), method = "pelt", change_in = "network"), ggchangepoint_unsupported = function(e) { paste("unsupported:", e$method, "offers", toString(e$supported)) } )res <- tryCatch(cpt_detect(c(1, 2), method = "pelt"), ggchangepoint_short_series = function(e) "too short") res # Branch on the kind of failure, not on its wording: tryCatch( cpt_detect(rnorm(50), method = "pelt", change_in = "network"), ggchangepoint_unsupported = function(e) { paste("unsupported:", e$method, "offers", toString(e$supported)) } )
The layers are real ggplot2 extensions: each geom_*() is a
layer built on one of these, with its own default aesthetics, required
aesthetics and legend glyph, so they take part in scales, guides and the
position system like any geom, and can be extended with
ggplot2::ggproto(). Until 0.6.0 every layer was a thin wrapper
around a stock geom and borrowed its glyph.
GeomChangepointa vertical rule at each xintercept
(geom_changepoint()); key: a vertical rule.
GeomCptSegmenta segment level
(geom_cpt_segment()).
GeomCptCia horizontal interval with caps
(geom_cpt_ci()); key: the same interval.
GeomCptRegiona band from xmin to xmax,
full height unless ymin/ymax are mapped
(geom_cpt_region()); key: a shaded band.
GeomCptLabela labelled interval behind the series
(geom_cpt_label()).
GeomCptEventa dotted rule with its label
(geom_cpt_event()); key: a dotted rule with a flag.
StatChangepoint, StatCptRegion
detection inside the
layer (stat_changepoint(),
stat_cpt_region()).
ggproto objects.
Other ggplot2 layers:
geom_changepoint(),
geom_cpt_ci(),
geom_cpt_event(),
geom_cpt_label(),
geom_cpt_region(),
geom_cpt_segment(),
stat_changepoint(),
stat_cpt_region()
library(ggplot2) class(GeomChangepoint) GeomCptRegion$default_aeslibrary(ggplot2) class(GeomChangepoint) GeomCptRegion$default_aes
Runs several detectors on the same data and returns a faceted or overlaid
ggplot comparison. Respects future::plan() for parallel execution
if the future.apply package is available.
ggcpt_compare( x, methods = c("pelt", "binseg", "amoc"), layout = c("facet", "overlay"), change_in = "mean", seed = NULL, ... )ggcpt_compare( x, methods = c("pelt", "binseg", "amoc"), layout = c("facet", "overlay"), change_in = "mean", seed = NULL, ... )
x |
A numeric vector (the data series). A one-column matrix or data
frame is accepted; wider input is refused, because these detectors are
univariate and flattening the columns would invent a changepoint at
every seam. Use |
methods |
Character vector of method names (passed to |
layout |
Layout type. |
change_in |
What to detect change in. Passed to each detector. |
seed |
Optional seed for reproducible parallelism. Passed to
|
... |
Additional arguments passed to each detector. |
A ggplot object.
Unlike cpt_detect(), cpt_batch() and
autoplot.ggcpt(), these two take no index: the
input is reduced to a bare numeric vector, so a ts, xts,
zoo or tsibble is plotted (and tabulated) in observation
positions with an "Index" axis. To compare detectors on dated data, run
cpt_detect(x, method = m, index = dates) per method and read
tidy()'s cp_index, or plot the results with
autoplot().
Running several methods and reporting the one that found a change, as
if it were the only one run, is a garden of forking paths with a plot
attached, and fifty methods behind one call make it easier here than
anywhere else. A method chosen because of its answer carries no valid
p-value, and neither does any test at its changepoints: the selection
across methods is a second selection on top of the one each method
already makes (see cpt_test()'s selection_adjusted).
Choose the method before seeing the data (cpt_recommend()
answers from what you know about the problem, not from the series), or
report every method you ran. Agreement across methods, as
cpt_consensus() counts it, is a robustness display, not a
correction: the methods share engines, costs and assumptions.
set.seed(2022) x <- c(rnorm(100, 0, 1), rnorm(100, 10, 1)) ggcpt_compare(x, methods = c("pelt", "binseg"))set.seed(2022) x <- c(rnorm(100, 0, 1), rnorm(100, 10, 1)) ggcpt_compare(x, methods = c("pelt", "binseg"))
Returns a tidy tibble combining the results of multiple detectors on the same series.
ggcpt_compare_table( x, methods = c("pelt", "binseg", "amoc"), change_in = "mean", ... )ggcpt_compare_table( x, methods = c("pelt", "binseg", "amoc"), change_in = "mean", ... )
x |
A numeric vector (the data series). A one-column matrix or data
frame is accepted; wider input is refused, because these detectors are
univariate and flattening the columns would invent a changepoint at
every seam. Use |
methods |
Character vector of method names. |
change_in |
What to detect change in. |
... |
Additional arguments passed to each detector. |
A tibble with columns method, cp, cp_value.
Other plotting:
ggcpt_eval(),
ggcpt_interactive(),
ggcptplot(),
ggecpplot()
set.seed(2026) x <- c(rnorm(100), rnorm(100, 5)) ggcpt_compare_table(x, methods = c("pelt", "binseg"))set.seed(2026) x <- c(rnorm(100), rnorm(100, 5)) ggcpt_compare_table(x, methods = c("pelt", "binseg"))
Overlays predictions and ground truth on the series with tolerance windows,
colouring true positives, false positives, and misses. Uses the same
one-to-one matching as cpt_metrics(), so the plot and the
metrics agree.
ggcpt_eval(pred, truth, data_vec = NULL, margin = 5)ggcpt_eval(pred, truth, data_vec = NULL, margin = 5)
pred |
Predicted changepoint indices, or a |
truth |
Ground truth changepoint indices. |
data_vec |
The original data vector (for context). Taken from
|
margin |
Tolerance margin (default 5). |
A ggplot object.
Other plotting:
ggcpt_compare_table(),
ggcpt_interactive(),
ggcptplot(),
ggecpplot()
set.seed(2026) x <- c(rnorm(100), rnorm(100, 5)) fit <- cpt_detect(x, method = "pelt") ggcpt_eval(fit$changepoints$cp, truth = 100, data_vec = x)set.seed(2026) x <- c(rnorm(100), rnorm(100, 5)) fit <- cpt_detect(x, method = "pelt") ggcpt_eval(fit$changepoints$cp, truth = 100, data_vec = x)
Renders a ggcpt result (or any ggplot built from one) as an
interactive HTML widget, with values on hover. A thin convenience
wrapper: the static autoplot() path is untouched.
ggcpt_interactive( x, engine = c("plotly", "ggiraph"), width_svg = 8, height_svg = 5, ... )ggcpt_interactive( x, engine = c("plotly", "ggiraph"), width_svg = 8, height_svg = 5, ... )
x |
A |
engine |
Which renderer: |
width_svg, height_svg
|
Figure size in inches for
|
... |
Additional arguments passed to |
A plotly or ggiraph htmlwidget.
Other plotting:
ggcpt_compare_table(),
ggcpt_eval(),
ggcptplot(),
ggecpplot()
res <- cpt_detect(c(rnorm(50), rnorm(50, 5)), method = "pelt") ggcpt_interactive(res)res <- cpt_detect(c(rnorm(50), rnorm(50, 5)), method = "pelt") ggcpt_interactive(res)
Convenience S3 methods for working with ggcpt objects: coerce the
changepoints to a tibble or data frame, render a one-line summary string, or
produce the default plot (a base-graphics fallback that delegates to
autoplot.ggcpt).
## S3 method for class 'ggcpt' as_tibble(x, ..., .name_repair = NULL) ## S3 method for class 'ggcpt' as.data.frame(x, row.names = NULL, optional = FALSE, ...) ## S3 method for class 'ggcpt' format(x, ...) ## S3 method for class 'ggcpt' plot(x, ...)## S3 method for class 'ggcpt' as_tibble(x, ..., .name_repair = NULL) ## S3 method for class 'ggcpt' as.data.frame(x, row.names = NULL, optional = FALSE, ...) ## S3 method for class 'ggcpt' format(x, ...) ## S3 method for class 'ggcpt' plot(x, ...)
x |
A |
... |
Additional arguments passed to methods. |
.name_repair |
Ignored (the changepoints tibble already has valid, unique names); present for signature compatibility with the generic. |
row.names, optional
|
Passed to |
as_tibble() and as.data.frame() return the changepoints
table; format() returns a length-one character string; plot()
draws the default plot and returns the ggplot object invisibly.
ggcpt_plot_methods for plot() on the other
result classes, and tidy.ggcpt() for the tidy accessors.
set.seed(2022) res <- cpt_detect(c(rnorm(50), rnorm(50, 5)), method = "pelt") as_tibble(res) as.data.frame(res) format(res)set.seed(2022) res <- cpt_detect(c(rnorm(50), rnorm(50, 5)), method = "pelt") as_tibble(res) as.data.frame(res) format(res)
Every result class in the package has an autoplot() method, but
plot() is the reflex most users reach for first. Without a method,
plot() on a list-shaped result falls through to
plot.default and fails with 'x' is a list, but
does not have components 'x' and 'y', a message that names neither this
package nor autoplot(). These methods delegate to the corresponding
autoplot() method so that plot(result) draws the intended
figure.
## S3 method for class 'ggcpt_selection' plot(x, ...) ## S3 method for class 'ggcpt_stability' plot(x, ...) ## S3 method for class 'ggcpt_sensitivity' plot(x, ...) ## S3 method for class 'ggcpt_influence' plot(x, ...) ## S3 method for class 'ggcpt_batch' plot(x, ...) ## S3 method for class 'ggcpt_benchmark' plot(x, ...) ## S3 method for class 'ggcpt_consensus' plot(x, ...) ## S3 method for class 'ggcpt_monitor' plot(x, ...) ## S3 method for class 'ggcpt_delay' plot(x, ...) ## S3 method for class 'ggcpt_path' plot(x, ...) ## S3 method for class 'ggcpt_power' plot(x, ...) ## S3 method for class 'ggcpt_effect' plot(x, ...) ## S3 method for class 'ggcpt_robustness' plot(x, ...) ## S3 method for class 'ggcpt_recommendation' plot(x, ...) ## S3 method for class 'ggcpt_events' plot(x, ...) ## S3 method for class 'ggcpt_label_curve' plot(x, ...)## S3 method for class 'ggcpt_selection' plot(x, ...) ## S3 method for class 'ggcpt_stability' plot(x, ...) ## S3 method for class 'ggcpt_sensitivity' plot(x, ...) ## S3 method for class 'ggcpt_influence' plot(x, ...) ## S3 method for class 'ggcpt_batch' plot(x, ...) ## S3 method for class 'ggcpt_benchmark' plot(x, ...) ## S3 method for class 'ggcpt_consensus' plot(x, ...) ## S3 method for class 'ggcpt_monitor' plot(x, ...) ## S3 method for class 'ggcpt_delay' plot(x, ...) ## S3 method for class 'ggcpt_path' plot(x, ...) ## S3 method for class 'ggcpt_power' plot(x, ...) ## S3 method for class 'ggcpt_effect' plot(x, ...) ## S3 method for class 'ggcpt_robustness' plot(x, ...) ## S3 method for class 'ggcpt_recommendation' plot(x, ...) ## S3 method for class 'ggcpt_events' plot(x, ...) ## S3 method for class 'ggcpt_label_curve' plot(x, ...)
x |
A result object created by one of the package's |
... |
Passed to the corresponding |
The plot is drawn as a side effect and the ggplot object is returned
invisibly, so plot() works inside a loop or a function while
p <- plot(result) still gives you the object to add layers to.
The ggplot object, invisibly. Called for the side effect of
drawing the plot.
autoplot.ggcpt; ggcpt_methods for the
ggcpt class itself.
set.seed(2024) x <- c(stats::rnorm(60), stats::rnorm(60, 4)) plot(cpt_select(x, method = "pelt", criterion = "bic", k_max = 4)) plot(cpt_crops(x, pen_min = 1, pen_max = 30)) # the object is still available to build on p <- plot(cpt_stability(x, method = "pelt", B = 20, seed = 1)) p + ggplot2::labs(title = "Bootstrap stability")set.seed(2024) x <- c(stats::rnorm(60), stats::rnorm(60, 4)) plot(cpt_select(x, method = "pelt", criterion = "bic", k_max = 4)) plot(cpt_crops(x, pen_min = 1, pen_max = 30)) # the object is still available to build on p <- plot(cpt_stability(x, method = "pelt", B = 20, seed = 1)) p + ggplot2::labs(title = "Bootstrap stability")
Draws the classic Bayesian changepoint display: the series with its
posterior mean (top panel) and the per-location posterior probability of
a changepoint (bottom panel). Works with results from
bcp_wrapper() and beast_wrapper().
ggcpt_posterior(x, prob_threshold = NULL)ggcpt_posterior(x, prob_threshold = NULL)
x |
A |
prob_threshold |
Probability cutoff drawn as a horizontal reference line in the probability panel; defaults to the threshold recorded on the object (or 0.5). |
A ggplot object (two facets sharing the x axis).
res <- bcp_wrapper(c(rnorm(60), rnorm(60, 4)), seed = 2026) ggcpt_posterior(res)res <- bcp_wrapper(c(rnorm(60), rnorm(60, 4)), seed = 2026) ggcpt_posterior(res)
Draws the signature BOCPD graphic: the posterior distribution of the run
length (time since the last changepoint) at every observation, as a
heatmap, with the series overlaid on top. Works with results from
bocpd_wrapper().
ggcpt_runlength(x, prob_floor = 0.001)ggcpt_runlength(x, prob_floor = 0.001)
x |
A |
prob_floor |
Posterior probabilities below this value are not drawn
(keeps the heatmap legible). Defaults to |
A ggplot object.
res <- bocpd_wrapper(c(rnorm(60), rnorm(60, 4))) ggcpt_runlength(res)res <- bocpd_wrapper(c(rnorm(60), rnorm(60, 4))) ggcpt_runlength(res)
The plot for changepoints detected by the changepoint package is a line plot for the raw data and the vertical lines representing each changepoint. The x-axis is the row number of the raw data in the original data vector. The plot inherits ggplot2, meaning users can add ggplot2 functions on top the changepoint plot for customization.
ggcptplot( data, change_in = "mean_var", cp_method = "PELT", ..., cptline_alpha = 1, cptline_color = "blue", cptline_type = "solid", cptline_linewidth = 0.5, cptline_size = lifecycle::deprecated(), index = NULL, show_points = NULL, show_line = TRUE )ggcptplot( data, change_in = "mean_var", cp_method = "PELT", ..., cptline_alpha = 1, cptline_color = "blue", cptline_type = "solid", cptline_linewidth = 0.5, cptline_size = lifecycle::deprecated(), index = NULL, show_points = NULL, show_line = TRUE )
data |
A numeric vector. |
change_in |
Choice of |
cp_method |
A wide range of choices (i.e., |
... |
Extra arguments for each |
cptline_alpha |
The value of alpha for the vertical changepoint line(s), default is 1, meaning no transparency. |
cptline_color |
The color for the vertical changepoint line(s), default
is |
cptline_type |
The linetype for the vertical changepoint line(s),
default is |
cptline_linewidth |
The linewidth for the vertical changepoint line(s),
default is |
cptline_size |
Deprecated. Use |
index |
Optional. A vector of x-axis labels (e.g. dates) of the same
length as |
show_points |
Logical. Whether to draw data points. Defaults to
|
show_line |
Logical. Whether to draw the line. Defaults to |
A line plot with data points along with the vertical lines representing changepoints.
Other plotting:
ggcpt_compare_table(),
ggcpt_eval(),
ggcpt_interactive(),
ggecpplot()
ggcptplot(c(rnorm(100,0,1),rnorm(100,0,10))) ggcptplot(c(rnorm(100,0,1),rnorm(100,10,1)))ggcptplot(c(rnorm(100,0,1),rnorm(100,0,10))) ggcptplot(c(rnorm(100,0,1),rnorm(100,10,1)))
The plot for changepoints detected by the ecp package is a line plot for the raw data and the vertical lines representing each changepoint. The x-axis is the row number of the raw data in the original data vector. The plot inherits ggplot2, meaning users can add ggplot2 functions on top the changepoint plot for customization.
ggecpplot( data, algorithm = "divisive", min_size = 2, ..., cptline_alpha = 1, cptline_color = "blue", cptline_type = "solid", cptline_linewidth = 0.5, cptline_size = lifecycle::deprecated(), index = NULL, show_points = NULL, show_line = TRUE )ggecpplot( data, algorithm = "divisive", min_size = 2, ..., cptline_alpha = 1, cptline_color = "blue", cptline_type = "solid", cptline_linewidth = 0.5, cptline_size = lifecycle::deprecated(), index = NULL, show_points = NULL, show_line = TRUE )
data |
A numeric vector (for univariate) or matrix/data.frame (for multivariate). |
algorithm |
Either |
min_size |
Minimum number of observations between change points. By
default is 2. This argument is only applied when |
... |
Extra arguments to pass on either from |
cptline_alpha |
The value of alpha for the vertical changepoint line(s), default is 1, meaning no transparency. |
cptline_color |
The color for the vertical changepoint line(s), default
is |
cptline_type |
The linetype for the vertical changepoint line(s),
default is |
cptline_linewidth |
The linewidth for the vertical changepoint line(s),
default is |
cptline_size |
Deprecated. Use |
index |
Optional. A vector of x-axis labels (e.g. dates) of the same
length as |
show_points |
Logical. Whether to draw data points. Defaults to
|
show_line |
Logical. Whether to draw the line. Defaults to |
A line plot with data points along with the vertical lines representing changepoints.
Other plotting:
ggcpt_compare_table(),
ggcpt_eval(),
ggcpt_interactive(),
ggcptplot()
ggecpplot(c(rnorm(100,0,1),rnorm(100,0,10))) ggecpplot(c(rnorm(100,0,1),rnorm(100,10,1)))ggecpplot(c(rnorm(100,0,1),rnorm(100,0,10))) ggecpplot(c(rnorm(100,0,1),rnorm(100,10,1)))
Returns a one-row summary of a changepoint detection result.
## S3 method for class 'ggcpt' glance(x, ...)## S3 method for class 'ggcpt' glance(x, ...)
x |
A |
... |
Additional arguments (ignored). |
total_cost is reported on whatever scale the engine itself uses, so
it is meaningful when comparing penalties within one method and not when
comparing one method against another. For the changepoint engines it
is the unpenalised of the chosen segmentation. Four cases
there are NA rather than filled with a number that would not mean
the same thing:
"binseg" and "segneigh", whose cpt.range
fits report the raw within-segment cost instead: for one and the same
segmentation that is 219.7 where a PELT fit reports 659.9;
"np", because changepoint.np defines no
logLik method;
a change in mean under the default "MBIC" penalty.
Loading changepoint.np (which this package imports, so it is
always loaded) replaces changepoint's logLik method for
cpt objects with one that errors on exactly that combination.
Any other penalty ("BIC", "AIC", a numeric value)
reports normally, as do change_in = "var" and
"meanvar".
A one-row tibble with columns: n, n_changepoints,
method, change_in, penalty_type, penalty_value,
cp_convention, total_cost (NA when the engine does
not expose a cost), runtime (elapsed seconds when measured by
cpt_detect(), otherwise NA) and engine_version
(the version of the engine package that produced the result, recorded
when it was made, or NA for a result with no engine package,
such as one built by as_ggcpt(); see
cpt_verify()) and family (the distribution family
the fit was asked for with cpt_detect(family = ), or NA
for the method's own default).
set.seed(2026) fit <- cpt_detect(c(rnorm(60), rnorm(60, 3)), method = "pelt") glance(fit)set.seed(2026) fit <- cpt_detect(c(rnorm(60), rnorm(60, 3)), method = "pelt") glance(fit)
Wraps changepoints::BS.cov() (Wang, Yu and Rinaldo): binary
segmentation on the sample covariance operator, which detects a change in
the dependence structure of a multivariate series even when every
marginal mean and variance is unchanged. No other engine in the package
can see that.
hdcov_wrapper( x, threshold = NULL, alpha = 0.05, n_perm = 20, delta = NULL, seed = NULL )hdcov_wrapper( x, threshold = NULL, alpha = 0.05, n_perm = 20, delta = NULL, seed = NULL )
x |
A numeric matrix or data frame, rows as time points. |
threshold |
Detection threshold on the CUSUM statistic. When
|
alpha |
Family-wise level for the permutation threshold. Defaults to
|
n_perm |
Permutations used to calibrate the threshold. Defaults to
|
delta |
Minimum spacing between changepoints. Defaults to
|
seed |
Optional seed (the permutation calibration is random). The
seed is scoped to this call: |
A ggcpt object with change_in = "covariance"; the
changepoints tibble carries the CUSUM statistic in cusum.
Wang D, Yu Y, Rinaldo A (2021). “Optimal covariance change point localization in high dimensions.” Bernoulli, 27(1), 554–575. doi:10.3150/20-BEJ1249.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) p <- 5 A <- matrix(rnorm(100 * p), ncol = p) B <- matrix(rnorm(100 * p), ncol = p) B[, 2] <- B[, 1] + 0.2 * B[, 2] # correlation appears hdcov_wrapper(rbind(A, B), n_perm = 20, alpha = 0.05, seed = 1)set.seed(2026) p <- 5 A <- matrix(rnorm(100 * p), ncol = p) B <- matrix(rnorm(100 * p), ncol = p) B[, 2] <- B[, 1] + 0.2 * B[, 2] # correlation appears hdcov_wrapper(rbind(A, B), n_perm = 20, alpha = 0.05, seed = 1)
Wraps changepoints::CV.search.DP.regression() (Rinaldo, Wang, Wen,
Willett and Yu): dynamic programming with an penalty for
changes in the coefficient vector of a high-dimensional sparse regression,
with the two tuning parameters chosen by cross-validation. Where
strucchange_wrapper() dates breaks in a low-dimensional
regression by dynamic programming on the residual sum of squares, this
handles the case where there are more covariates than the segments have
observations to fit them with.
hdreg_wrapper( x, response = NULL, gamma_set = NULL, lambda_set = NULL, delta = NULL, ... )hdreg_wrapper( x, response = NULL, gamma_set = NULL, lambda_set = NULL, delta = NULL, ... )
x |
A numeric matrix or data frame of covariates, rows as time points. |
response |
A numeric vector of responses, one per row of |
gamma_set |
Candidate values of the |
lambda_set |
Candidate lasso penalties. Defaults to
|
delta |
Minimum spacing. Defaults to |
... |
Additional arguments passed to the engine. |
A ggcpt object with change_in = "regression". The
plotted series is the response, which is what a reader of a
regression-break plot expects to see.
Rinaldo A, Wang D, Wen Q, Willett R, Yu Y (2021). “Localizing changes in high-dimensional regression models.” In Proceedings of the 24th International Conference on Artificial Intelligence and Statistics, volume 130 of Proceedings of Machine Learning Research, 2089–2097.
var_wrapper(), strucchange_wrapper().
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) p <- 10 n <- 80 X <- matrix(stats::rnorm(n * p), n, p) beta1 <- c(rep(2, 3), rep(0, p - 3)) beta2 <- c(rep(0, p - 3), rep(2, 3)) y <- c(X[1:40, ] %*% beta1, X[41:n, ] %*% beta2) + stats::rnorm(n) hdreg_wrapper(X, response = y, gamma_set = c(1, 10), lambda_set = c(0.1, 1))set.seed(2026) p <- 10 n <- 80 X <- matrix(stats::rnorm(n * p), n, p) beta1 <- c(rep(2, 3), rep(0, p - 3)) beta2 <- c(rep(0, p - 3), rep(2, 3)) y <- c(X[1:40, ] %*% beta1, X[41:n, ] %*% beta2) + stats::rnorm(n) hdreg_wrapper(X, response = y, gamma_set = c(1, 10), lambda_set = c(0.1, 1))
Wraps the IDetect package. Requires the IDetect package.
idetect_wrapper(x, seed = NULL, ...)idetect_wrapper(x, seed = NULL, ...)
x |
A numeric vector. |
seed |
Optional seed for reproducibility. The seed is scoped to this
call: |
... |
Additional arguments passed to |
A ggcpt object. When the engine finds no changepoints
(including when it signals "No change-points found"), an empty result
is returned rather than an error. A constant series likewise returns the
empty result; see the note below.
IDetect::ID() does not treat a flat series consistently: its
statistics become , and what comes back depends on the value and
the length. rep(3, 200) yields 126 changepoints, at
1, 3, 4, 6, 7, ...; rep(0, 100) raises "No change-points found";
rep(-2.5, 60) returns the sentinel 0. A constant series plainly has
no changepoint, and every other search wrapper here reports none, so this
one short-circuits to the empty result. Constancy is decided by exact
equality, so a series with tiny but genuine variation still reaches the
engine.
Anastasiou A, Fryzlewicz P (2022). “Detecting Multiple Generalized Change-Points by Isolating Single Ones.” Metrika, 85, 141–174. doi:10.1007/s00184-021-00821-6.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) idetect_wrapper(c(rnorm(60), rnorm(60, 4)))$changepoints # a flat series has no changepoint; see "Constant input" above nrow(idetect_wrapper(rep(3, 100))$changepoints)set.seed(2026) idetect_wrapper(c(rnorm(60), rnorm(60, 4)))$changepoints # a flat series has no changepoint; see "Constant input" above nrow(idetect_wrapper(rep(3, 100))$changepoints)
Wraps InspectChangepoint::inspect() (Wang and Samworth, 2018). For
a -variate series whose mean changes in an unknown sparse subset of
coordinates, the algorithm computes the CUSUM transformation, finds the
optimal sparse projection direction via a convex relaxation, and locates
changepoints on the projected univariate series, recursing via wild binary
segmentation.
inspect_wrapper(x, lambda = NULL, threshold = NULL, ...)inspect_wrapper(x, lambda = NULL, threshold = NULL, ...)
x |
A numeric matrix or data frame with one row per time point and one column per coordinate. |
lambda |
Regularisation parameter of the sparse projection; when
|
threshold |
Detection threshold; when |
... |
Additional arguments passed to
|
A ggcpt object. The changepoints tibble carries a
strength column (the maximum projected CUSUM statistic). The
first coordinate is used for cp_value and the univariate plot
line; the full matrix is kept for the faceted multivariate
autoplot(). Coordinates that are constant carry no changepoint
information and would make the engine's variance rescaling undefined, so
they are dropped (with a warning) before detection and an all-constant
matrix returns an empty result; the dropped coordinates are still kept
for plotting, and reported locations always refer to the original rows.
Wang T, Samworth RJ (2018). “High dimensional change point estimation via sparse projection.” Journal of the Royal Statistical Society: Series B, 80(1), 57–83.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) X <- cbind(c(rnorm(80), rnorm(80, 3)), c(rnorm(80), rnorm(80, -2)), rnorm(160)) res <- inspect_wrapper(X) res$changepointsset.seed(2026) X <- cbind(c(rnorm(80), rnorm(80, 3)), c(rnorm(80), rnorm(80, -2)), rnorm(160)) res <- inspect_wrapper(X) res$changepoints
A class check, useful when a function accepts either a detection result or
the raw series. It tests for ggcpt in the class vector, so a
genuine ggcpt subclass (ggcpt_consensus is the one)
returns TRUE. The other ggcpt_* classes in the package
(ggcpt_batch, ggcpt_benchmark, ggcpt_monitor,
ggcpt_selection and the rest) are not subclasses of
ggcpt (most are tibble subclasses) and return
FALSE.
is_ggcpt(x)is_ggcpt(x)
x |
An object to test. |
TRUE if x inherits from ggcpt.
Other result class:
annotate_segments(),
as_cpt_series(),
as_ggcpt(),
as_json(),
cpt_annotations(),
cpt_export(),
cpt_verify(),
ggchangepoint-conditions,
new_ggcpt(),
print.ggcpt()
set.seed(2026) fit <- cpt_detect(c(rnorm(40), rnorm(40, 4)), method = "pelt") is_ggcpt(fit) is_ggcpt(fit$changepoints)set.seed(2026) fit <- cpt_detect(c(rnorm(40), rnorm(40, 4)), method = "pelt") is_ggcpt(fit) is_ggcpt(fit$changepoints)
Wraps kcpRS::kcpRS() (Cabrieto et al., 2018; the KCP framework of
Arlot, Celisse and Harchaoui, 2019). The data are mapped to a running
statistic (mean, variance, autocorrelation, or correlation) computed on a
sliding window, and a Gaussian-kernel change point analysis with a
permutation significance test is run on the statistic. Detecting changes
in running correlations or variances captures higher-order changes that
mean-based methods miss. Multivariate input (matrix or data frame) is
supported.
kcp_wrapper( x, running_stat = c("mean", "var", "autocorr", "corr"), wsize = 25, nperm = 1000, kmax = 10, alpha = 0.05, seed = NULL, ... )kcp_wrapper( x, running_stat = c("mean", "var", "autocorr", "corr"), wsize = 25, nperm = 1000, kmax = 10, alpha = 0.05, seed = NULL, ... )
x |
A numeric vector, matrix, or data frame (columns are variables). |
running_stat |
Which running statistic to monitor: |
wsize |
Sliding window size for the running statistic. Defaults to
|
nperm |
Number of permutations for the significance test, at least 2.
Defaults to |
kmax |
Maximum number of changepoints considered. Defaults to
|
alpha |
Significance level of the permutation test. Defaults to
|
seed |
Optional seed for reproducibility of the permutation test.
The seed is scoped to this call: |
... |
Additional arguments passed to |
A ggcpt object. Reported locations refer to the centre of
the sliding window in which the change occurs. The series must be at
least wsize long to form one window. Constant coordinates make
every running statistic NA, so they are dropped (with a warning)
before detection and an all-constant input returns an empty result.
Arlot S, Celisse A, Harchaoui Z (2019). “A kernel multiple change-point algorithm via model selection.” Journal of Machine Learning Research, 20(162), 1–56.
Cabrieto J, Adolf J, Tuerlinckx F, Kuppens P, Ceulemans E (2018). “Detecting long-lived autodependency changes in a multivariate system via change point detection and regime switching models.” Scientific Reports, 8, 15637.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
res <- kcp_wrapper(c(rnorm(60), rnorm(60, 3)), nperm = 100, seed = 2026) res$changepointsres <- kcp_wrapper(c(rnorm(60), rnorm(60, 3)), nperm = 100, seed = 2026) res$changepoints
Wraps KWCChangepoint (Ramsay and Chenouri): the functional Kruskal-Wallis covariance test, which ranks observations by statistical depth and segments on the ranks. Because it never touches the values themselves it is insensitive to heavy tails and outlying curves, which is exactly where the moment-based functional tests degrade.
kwc_wrapper( x, algorithm = c("fkwc", "dwbs"), depth = NULL, change_in = c("covariance", "distribution"), seed = NULL, ... )kwc_wrapper( x, algorithm = c("fkwc", "dwbs"), depth = NULL, change_in = c("covariance", "distribution"), seed = NULL, ... )
x |
A numeric matrix or data frame with one row per observation (time point) and one column per grid location or coordinate. |
algorithm |
|
depth |
Depth function. For |
change_in |
Reported change type: |
seed |
Optional seed: the random-projection depths and the wild
binary segmentation both randomise. The seed is scoped to this call:
|
... |
Additional arguments passed to the engine. |
A ggcpt object. Multivariate input is
reduced to one series per observation by taking the
cross-sectional mean of the columns, and that is the series stored on
the result: autoplot() draws it, tidy()'s
cp_value reads it, and $segments$param_estimate and
augment()'s .fitted/.resid are computed from it.
It is not any one column of the input. The full input is kept in
$data_wide for autoplot(type = "coordinates").
Ramsay K, Chenouri S (2025). “Robust changepoint detection in the variability of multivariate functional data.” Journal of Nonparametric Statistics. doi:10.1080/10485252.2025.2503891.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) X <- matrix(rnorm(100 * 20), nrow = 100) X[51:100, ] <- X[51:100, ] * 3 kwc_wrapper(X, seed = 1)set.seed(2026) X <- matrix(rnorm(100 * 20), nrow = 100) X[51:100, ] <- X[51:100, ] * 3 kwc_wrapper(X, seed = 1)
Wraps mcp::mcp() (Lindeløv): a Bayesian multiple-changepoint
regression specified as a list of formulas, one per segment. This
is the most expressive detector in the package: each segment can have its
own intercept, slope, variance and autocorrelation, and the changepoints
themselves get full posterior distributions rather than point estimates,
summarised here as ci_lower/ci_upper on the changepoints
tibble. (ggcpt_posterior() draws a per-location
probability profile, which only bcp and Rbeast expose; it
does not accept an mcp result.)
mcp_wrapper( x, change_in = c("mean", "slope", "var"), n_changepoints = 1, model = NULL, prior = list(), iter = 3000, adapt = 1000, chains = 3, seed = NULL, ... )mcp_wrapper( x, change_in = c("mean", "slope", "var"), n_changepoints = 1, model = NULL, prior = list(), iter = 3000, adapt = 1000, chains = 3, seed = NULL, ... )
x |
A numeric vector. |
change_in |
Shorthand for the segment model when |
n_changepoints |
Number of changepoints in the shorthand model.
Defaults to |
model |
An explicit mcp model: a list of formulas. Overrides
|
prior |
Optional named list of priors, passed to |
iter, adapt, chains
|
Sampler settings, passed through. |
seed |
Optional seed. The seed is scoped to this call:
|
... |
Additional arguments passed to |
A ggcpt object. The changepoints tibble carries the
posterior mean location together with ci_lower/ci_upper
from the posterior quantiles, each converted from mcp's
continuous cp_1, cp_2, ... to the last observation
before the change (ceiling(cp) - 1, because mcp starts a
segment at x >= cp), and $data$fitted holds the
posterior predictive mean, so autoplot(show_ci = TRUE,
show_fit = TRUE) shows both.
mcp samples through JAGS, a separate program installed outside R.
Having the package is not the same as being able to run it:
mcp imports rjags, and on some platforms rjags
installs happily and only fails when it looks for the JAGS library at run
time, in which case mcp::mcp() returns a fit carrying no
posterior samples, with a warning rather than an error. This wrapper
checks for that and says so plainly instead of failing several frames
later inside summary(). Everything else in the package works
without JAGS.
Lindeløv JK (2020). “mcp: An R package for regression with multiple change points.” OSF Preprints. doi:10.31219/osf.io/fzqxv.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
# Not run by R CMD check: whether this works depends on a *system* # library, and no test of installed R packages predicts that reliably -- # `rjags` can be present and still fail to find JAGS at run time. ## Not run: set.seed(2026) fit <- mcp_wrapper(c(rnorm(60), rnorm(60, 4)), iter = 500, adapt = 200) fit ## End(Not run)# Not run by R CMD check: whether this works depends on a *system* # library, and no test of installed R packages predicts that reliably -- # `rjags` can be present and still fail to find JAGS at run time. ## Not run: set.seed(2026) fit <- mcp_wrapper(c(rnorm(60), rnorm(60, 4)), iter = 500, adapt = 200) fit ## End(Not run)
Wraps the mosum package for moving-sum-based changepoint
detection, either at a single bandwidth or (with
multiscale = TRUE) across a bandwidth grid with localised pruning.
mosum_wrapper(x, G = NULL, multiscale = FALSE, seed = NULL, ...)mosum_wrapper(x, G = NULL, multiscale = FALSE, seed = NULL, ...)
x |
A numeric vector. |
G |
Bandwidth. If |
multiscale |
Logical. Use the multiscale MOSUM procedure
( |
seed |
Optional seed for reproducibility. The seed is scoped to this
call: |
... |
Additional arguments passed to |
A ggcpt object.
Eichinger B, Kirch C (2018). “A MOSUM Procedure for the Estimation of Multiple Random Change Points.” Bernoulli, 24(1), 526–564. doi:10.3150/16-BEJ887.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) x <- c(rnorm(100), rnorm(100, 3)) mosum_wrapper(x, G = 20)$changepoints mosum_wrapper(x, multiscale = TRUE)$changepointsset.seed(2026) x <- c(rnorm(100), rnorm(100, 3)) mosum_wrapper(x, G = 20)$changepoints mosum_wrapper(x, multiscale = TRUE)$changepoints
Wraps changepoints::WBS.network() (Yu, Padilla, Wang and Rinaldo):
wild binary segmentation on a sequence of networks, detecting the times at
which the edge-probability structure changes. The input is one row per
time point holding the vectorised adjacency matrix, so a series of
networks over times is an
matrix.
network_wrapper( x, copy2 = NULL, n_intervals = 100, threshold = NULL, alpha = 0.05, n_perm = 20, delta = NULL, seed = NULL )network_wrapper( x, copy2 = NULL, n_intervals = 100, threshold = NULL, alpha = 0.05, n_perm = 20, delta = NULL, seed = NULL )
x |
The network sequence: an |
copy2 |
An independent second observation of the same network sequence, in the same shape. The method's guarantees rest on sample splitting; see the section below for what happens when there is only one copy. |
n_intervals |
Number of random intervals. Defaults to |
threshold |
Detection threshold. When |
alpha, n_perm
|
Level and number of permutations for that calibration. |
delta |
Minimum spacing. Defaults to |
seed |
Optional seed. The seed is scoped to this call:
|
A ggcpt object with change_in = "network". The
series it carries (and so the one autoplot() draws) is the
mean edge weight at each time point, rowMeans() of the
vectorised adjacency matrices. This is the one multivariate method with
no data_wide slot: a network has
entries per time point, so a facet per coordinate would be unreadable.
The changepoints are estimated from the networks themselves, not from
the summary.
WBS.network() takes two independent observations of the sequence,
which is how the theory controls the bias of the squared-Frobenius
statistic. Given a single sequence of binary networks this wrapper
constructs the second copy by splitting each edge indicator at random
(each present edge is assigned to one copy with probability one half),
which is the usual independent-thinning device and is reported in a
message. For weighted networks it splits the weight instead, which is
exact for Poisson weights and approximate otherwise. If you have a genuine
replicate, pass it as copy2 and none of this applies.
Yu Y, Padilla OHM, Wang D, Rinaldo A (2021). “Optimal network online change point localisation.” arXiv preprint arXiv:2101.05477. doi:10.48550/arXiv.2101.05477.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) p <- 5 mk <- function(n, prob) { t(replicate(n, as.numeric(matrix(stats::rbinom(p * p, 1, prob), p)))) } X <- rbind(mk(40, 0.2), mk(40, 0.6)) network_wrapper(X, n_intervals = 20, n_perm = 20, seed = 1)set.seed(2026) p <- 5 mk <- function(n, prob) { t(replicate(n, as.numeric(matrix(stats::rbinom(p * p, 1, prob), p)))) } X <- rbind(mk(40, 0.2), mk(40, 0.6)) network_wrapper(X, n_intervals = 20, n_perm = 20, seed = 1)
The low-level constructor for the class every detector in this package
returns. It assembles the components into a ggcpt without checking
them, which is what makes it useful inside a wrapper and unsuitable as the
entry point for hand-built input; use as_ggcpt() for that.
new_ggcpt( changepoints = tibble::tibble(cp = integer(), cp_value = numeric()), segments = tibble::tibble(seg_id = integer(), start = integer(), end = integer(), n = integer(), param_estimate = numeric()), data = tibble::tibble(index = integer(), value = numeric()), method = NA_character_, change_in = NA_character_, penalty = list(type = NA_character_, value = NA_real_), fit = NULL, call = NULL, cp_convention = "left", runtime = NA_real_ )new_ggcpt( changepoints = tibble::tibble(cp = integer(), cp_value = numeric()), segments = tibble::tibble(seg_id = integer(), start = integer(), end = integer(), n = integer(), param_estimate = numeric()), data = tibble::tibble(index = integer(), value = numeric()), method = NA_character_, change_in = NA_character_, penalty = list(type = NA_character_, value = NA_real_), fit = NULL, call = NULL, cp_convention = "left", runtime = NA_real_ )
changepoints |
A tibble with columns |
segments |
A tibble with segment information: |
data |
A tibble with |
method |
Character. The detection method used. A length-one string;
defaults to |
change_in |
Character. What was detected (e.g. "mean", "var",
"meanvar"). A length-one string; defaults to |
penalty |
A list with |
fit |
The raw upstream object. Every wrapper stores one except
|
call |
The matched call. |
cp_convention |
Character. The convention for reporting changepoint
locations: |
runtime |
Numeric. Elapsed detection time in seconds, if measured.
Defaults to |
An object of class ggcpt, holding exactly the
components passed in (documented one by one above) plus any of the
optional slots listed below. Nothing is validated or derived:
as_ggcpt() is the constructor that does both.
Beyond the components in the signature, a ggcpt may carry any of
these, each present only when something supplied it and each safe to test
for with is.null():
data_wideindex plus one column per coordinate, for a multivariate result.
index, index_label
a time index (one value per
observation) and its axis label; see the index argument of
cpt_detect().
regionsa tibble of significance regions
(start, end, ...) for the interval-valued methods;
see nsp_wrapper() and geom_cpt_region().
diagnosticsa named list of engine internals rendered by
ggcpt_statistic(),
ggcpt_solution_path() and
ggcpt_scale_space().
registeredTRUE when the result came from a
user-registered detector rather than a wired engine.
as_ggcpt() is the validating way to build one of these from
the outside; this constructor does not check its arguments.
Other result class:
annotate_segments(),
as_cpt_series(),
as_ggcpt(),
as_json(),
cpt_annotations(),
cpt_export(),
cpt_verify(),
ggchangepoint-conditions,
is_ggcpt(),
print.ggcpt()
set.seed(2026) new_ggcpt( changepoints = tibble::tibble(cp = 50L, cp_value = 0.1), data = tibble::tibble(index = 1:100, value = c(rnorm(50), rnorm(50, 4))), method = "manual", change_in = "mean")set.seed(2026) new_ggcpt( changepoints = tibble::tibble(cp = 50L, cp_value = 0.1), data = tibble::tibble(index = 1:100, value = c(rnorm(50), rnorm(50, 4))), method = "manual", change_in = "mean")
Wraps the not package for changepoint detection via the
Narrowest-Over-Threshold method. The contrast determines what change is
detected: piecewise-constant mean (default), mean and variance, or
(continuous or discontinuous) piecewise-linear trend.
not_wrapper(x, contrast = "pcwsConstMean", seed = NULL, ...)not_wrapper(x, contrast = "pcwsConstMean", seed = NULL, ...)
x |
A numeric vector. |
contrast |
Contrast type. One of |
seed |
Optional seed for reproducibility. The seed is scoped to this
call: |
... |
Additional arguments passed to |
A ggcpt object whose change_in reflects the
contrast: "mean", "meanvar", or "slope".
Baranowski R, Chen Y, Fryzlewicz P (2019). “Narrowest-Over-Threshold Detection of Multiple Change Points and Change-Point-Like Features.” Journal of the Royal Statistical Society Series B, 81(3), 649–672. doi:10.1111/rssb.12322.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) not_wrapper(c(rnorm(60), rnorm(60, 4)))$changepoints # a change in slope, not in level: pick the contrast to match trend <- c(1:60, 60 - 1:60) / 10 + rnorm(120) not_wrapper(trend, contrast = "pcwsLinContMean")$changepointsset.seed(2026) not_wrapper(c(rnorm(60), rnorm(60, 4)))$changepoints # a change in slope, not in level: pick the contrast to match trend <- c(1:60, 60 - 1:60) / 10 + rnorm(120) not_wrapper(trend, contrast = "pcwsLinContMean")$changepoints
Wraps CptNonPar::np.mojo() (McGonigle and Cho, 2025): nonparametric
moving-sum detection of changes in the marginal or joint distribution of a
(possibly multivariate) time series, robust to serial dependence.
npmojo_wrapper(x, G = NULL, lag = 0, ...)npmojo_wrapper(x, G = NULL, lag = 0, ...)
x |
A numeric vector or matrix (rows are time points). |
G |
Moving-window bandwidth. Defaults to |
lag |
Time lag at which changes in the joint distribution are
examined; |
... |
Additional arguments passed to |
A ggcpt object. Constant coordinates leave the kernel
statistics undefined, so they are dropped (with a warning) before
detection and an all-constant input returns an empty result. The
engine calibrates its detection threshold by bootstrap, so the value
recorded in the penalty descriptor varies between runs; call
set.seed() beforehand, or pass threshold = "manual" and
threshold.val through ..., for a reproducible one.
McGonigle ET, Cho H (2025). “Nonparametric data segmentation in multivariate time series via joint characteristic functions.” Biometrika, 112(2), asaf024.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
res <- npmojo_wrapper(c(rnorm(100), rnorm(100, 3))) res$changepointsres <- npmojo_wrapper(c(rnorm(100), rnorm(100, 3))) res$changepoints
Wraps the nsp package (Fryzlewicz 2024). NSP inverts the usual
framing of post-selection inference: rather than estimating changepoint
locations and then asking whether they are real, it returns a set of
intervals, each of which contains at least one changepoint, with
the guarantee holding globally across all intervals simultaneously
at level alpha. The guarantee is exact and finite-sample, and the
self-normalised and autoregressive variants keep it under heavy tails,
heteroscedasticity and serial dependence.
nsp_wrapper( x, alpha = 0.1, variant = c("poly", "selfnorm", "ar", "tvreg"), change_in = c("mean", "slope"), deg = NULL, M = 1000, covariates = NULL, ord = 1, seed = NULL, ... )nsp_wrapper( x, alpha = 0.1, variant = c("poly", "selfnorm", "ar", "tvreg"), change_in = c("mean", "slope"), deg = NULL, M = 1000, covariates = NULL, ord = 1, seed = NULL, ... )
x |
A numeric vector. |
alpha |
Global significance level: with probability at least
|
variant |
Which NSP procedure to run:
|
change_in |
|
deg |
Degree of the piecewise polynomial. Derived from
|
M |
Number of intervals drawn. Defaults to |
covariates |
A design matrix for |
ord |
AR order for |
seed |
Optional seed. NSP draws random intervals, so a run is
reproducible only with one. The seed is scoped to this call:
|
... |
Additional arguments passed to the underlying nsp function. |
A ggcpt object with a populated regions slot.
cp means here, and what it does notNSP produces no point estimates. This wrapper still fills the cp
column (with the midpoint of each interval) because every
downstream consumer in the package (augment(),
cpt_metrics(), cpt_consensus(),
autoplot()) is built on that column, and a result with an empty
cp would silently score as "found nothing". The midpoint is
not an estimate of the changepoint location and must not be
reported as one: the interval is the inferential object. The result
therefore
carries the intervals in a regions slot, read with
cpt_regions();
marks itself, so print() says the cp column is a
midpoint and autoplot() shades the bands by default;
adds a cp_source column reading
"region_midpoint" to the changepoints tibble.
Fryzlewicz P (2024). “Narrowest significance pursuit: inference for multiple change-points in linear models.” Journal of the American Statistical Association, 119(546), 1633–1646. doi:10.1080/01621459.2023.2211733.
cpt_regions(), geom_cpt_region(),
cpt_confint().
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) x <- c(rnorm(100), rnorm(100, 4)) fit <- nsp_wrapper(x, M = 100, seed = 1) cpt_regions(fit) ggplot2::autoplot(fit)set.seed(2026) x <- c(rnorm(100), rnorm(100, 4)) fit <- nsp_wrapper(x, M = 100, seed = 1) cpt_regions(fit) ggplot2::autoplot(fit)
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.
ocd_wrapper( x, train = NULL, thresh = "MC", patience = 5000, beta = 1, mc_reps = 100, ... )ocd_wrapper( x, train = NULL, thresh = "MC", patience = 5000, beta = 1, mc_reps = 100, ... )
x |
A numeric matrix or data frame with one row per time point and at
least two columns. The |
train |
Number of initial observations used to estimate the baseline
mean/sd (not monitored). Defaults to
|
thresh |
Threshold specification passed to
|
patience |
Target average run length to false alarm. Defaults to
|
beta |
Assumed lower bound on the squared Euclidean norm of the mean
change. Defaults to |
mc_reps |
Monte Carlo repetitions for threshold calibration.
Defaults to |
... |
Additional arguments passed to
|
A ggcpt object. Because the detector is online, it
declares a change without estimating where it began. cp is the
declaration time minus one: the latest changepoint consistent
with the alarm in this package's convention (the last observation
before the change), and exact when the change is declared on the first
observation after it; a later declaration makes cp late by the
detection delay. The declared_at column holds the declaration
time itself. (Before 0.6.0 cp was the declaration time, one
position late even at zero delay, which the convention test found.)
Compare cpm_wrapper(), whose engine estimates the
location separately from its detection_time.
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 , 22 s at and 113 s at
; raising mc_reps scales it linearly, so at
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 . 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 . 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.
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.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
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$changepointsset.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
Wraps HDCD::Pilliat() (Pilliat, Carpentier and Verzelen, 2023): a
high-dimensional mean-change procedure combining a dense test, a
Berk-Jones test and a partial-sum test, so it is powerful across sparsity
regimes without estimating the sparsity level. A useful cross-check on
esac_wrapper(): the two adapt differently and disagreeing
answers are informative.
pilliat_wrapper( x, threshold_d_const = 4, threshold_bj_const = 6, threshold_partial_const = 4, empirical = FALSE, N = 100, seed = NULL, ... )pilliat_wrapper( x, threshold_d_const = 4, threshold_bj_const = 6, threshold_partial_const = 4, empirical = FALSE, N = 100, seed = NULL, ... )
x |
A numeric matrix or data frame with rows as time points and columns as coordinates. |
threshold_d_const, threshold_bj_const, threshold_partial_const
|
Leading constants of the dense, Berk-Jones and partial-sum thresholds. |
empirical |
Calibrate the thresholds by Monte Carlo rather than using
the theoretical values? Slower but sharper; defaults to |
N |
Monte Carlo samples when |
seed |
Optional seed (used by the empirical calibration). The seed
is scoped to this call: |
... |
Additional arguments passed to |
A ggcpt object.
HDCD 1.1's Pilliat() builds one fewer partial-sum threshold
than it uses whenever the number of coordinates is an exact power of two,
so the C routine reads past the end of that vector and the engine reports
a changepoint at every observation, on pure noise as readily as on
a real change. This wrapper refuses those dimensions rather than returning
the result, because it is wrong in a way that looks like a finding.
esac_wrapper() is unaffected at every dimension. Note that
constant coordinates are dropped before the count, so 9 coordinates one of
which is constant is 8 for this purpose.
The same reasoning makes this the one engine that errors on a
degenerate segmentation (a changepoint at more than 90% of
observations) where every other engine in the package warns and reports
what it found. That has a consequence for comparisons:
cpt_batch() and cpt_benchmark() record a
failure row for pilliat where the same output from pelt
gives a result plus a warning, so a benchmark table is not scoring the
two on equal terms in that case; read the error column
alongside the metrics.
Pilliat E, Carpentier A, Verzelen N (2023). “Optimal multiple change-point detection for high-dimensional data.” Electronic Journal of Statistics, 17(1), 1240–1315. doi:10.1214/23-EJS2126.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) X <- matrix(rnorm(100 * 20), nrow = 100) X[51:100, 1:5] <- X[51:100, 1:5] + 3 pilliat_wrapper(X)set.seed(2026) X <- matrix(rnorm(100 * 20), nrow = 100) X[51:100, 1:5] <- X[51:100, 1:5] + 3 pilliat_wrapper(X)
The point of detecting a regime change is usually that the earlier
regime should no longer inform what happens next. predict() on a
ggcpt forecasts from one segment only (by default the last), with
the segment's own model.
## S3 method for class 'ggcpt' predict( object, newdata = NULL, h = 1, segment = "last", models = NULL, level = 0.95, ... )## S3 method for class 'ggcpt' predict( object, newdata = NULL, h = 1, segment = "last", models = NULL, level = 0.95, ... )
object |
A |
newdata |
Optional data frame of covariates (for a formula fit, or a
segment model with covariates), or of |
h |
Forecast horizon, when |
segment |
Which segment to forecast from: |
models |
Optional |
level |
Level of the prediction interval. Defaults to |
... |
Further arguments for the model's |
A tibble with time (when forecasting by horizon),
.pred, and .lower/.upper when the model supplies
a prediction interval.
Other segment models:
cpt_segment_models()
set.seed(1) fit <- cpt_detect(c(rnorm(100), rnorm(100, 3)), method = "pelt") predict(fit, h = 3)set.seed(1) fit <- cpt_detect(c(rnorm(100), rnorm(100, 3)), method = "pelt") predict(fit, h = 3)
A compact header (method, what changed, how many changepoints, the
convention their locations follow, the penalty and the series length)
followed by the first ten changepoints. For the segment table and the
fitted parameters use summary(); for the changepoints
as data use tidy().
## S3 method for class 'ggcpt' print(x, ...)## S3 method for class 'ggcpt' print(x, ...)
x |
A |
... |
Additional arguments (ignored). |
x, invisibly. Called for the side effect of printing.
summary.ggcpt(), tidy.ggcpt().
Other result class:
annotate_segments(),
as_cpt_series(),
as_ggcpt(),
as_json(),
cpt_annotations(),
cpt_export(),
cpt_verify(),
ggchangepoint-conditions,
is_ggcpt(),
new_ggcpt()
set.seed(2026) print(cpt_detect(c(rnorm(40), rnorm(40, 4)), method = "pelt"))set.seed(2026) print(cpt_detect(c(rnorm(40), rnorm(40, 4)), method = "pelt"))
The discrete palette used wherever this package colours by method, series or class. It is the Okabe-Ito qualitative palette, which stays distinguishable under deuteranopia, protanopia and tritanopia, extended by recycling with a linetype change so that colour is never the only channel carrying the distinction.
scale_colour_cpt(..., na.value = "grey70") scale_color_cpt(..., na.value = "grey70") scale_fill_cpt(..., na.value = "grey70") scale_linetype_cpt(...)scale_colour_cpt(..., na.value = "grey70") scale_color_cpt(..., na.value = "grey70") scale_fill_cpt(..., na.value = "grey70") scale_linetype_cpt(...)
... |
Passed to |
na.value |
Colour for missing values. |
A ggplot2 scale.
theme_ggcpt(),
scale_fill_cpt_label().
Other accessibility scales:
scale_fill_cpt_label(),
theme_ggcpt()
library(ggplot2) ggplot(mtcars, aes(wt, mpg, colour = factor(cyl))) + geom_point() + scale_colour_cpt() + theme_ggcpt()library(ggplot2) ggplot(mtcars, aes(wt, mpg, colour = factor(cyl))) + geom_point() + scale_colour_cpt() + theme_ggcpt()
A colour-vision-deficiency-safe fill scale covering both vocabularies the
supervised-detection displays use: the label's assertion
(change / no_change / one_change) and the outcome of
scoring a segmentation against it (correct / false_positive
/ false_negative). Unknown values fall back to grey rather than
erroring, so a partially-scored frame still plots.
scale_fill_cpt_label(..., na.value = "grey70") scale_colour_cpt_label(..., na.value = "grey70")scale_fill_cpt_label(..., na.value = "grey70") scale_colour_cpt_label(..., na.value = "grey70")
... |
Passed to |
na.value |
Fill for values outside the vocabulary. |
A ggplot2 scale.
Other accessibility scales:
scale_colour_cpt(),
theme_ggcpt()
library(ggplot2) labs <- cpt_labels(c(40, 70), c(60, 90), c("change", "no_change")) ggplot(labs, aes(xmin = start, xmax = end, ymin = 0, ymax = 1, fill = change)) + geom_rect() + scale_fill_cpt_label() # the same palette covers correct / false_positive / false_negative class(scale_colour_cpt_label())library(ggplot2) labs <- cpt_labels(c(40, 70), c(60, 90), c("change", "no_change")) ggplot(labs, aes(xmin = start, xmax = end, ymin = 0, ymax = 1, fill = change)) + geom_rect() + scale_fill_cpt_label() # the same palette covers correct / false_positive / false_negative class(scale_colour_cpt_label())
Wraps segmented::segmented() (Muggeo, 2003, 2008): maximum
likelihood estimation of continuous piecewise-linear
("broken-line") regressions, with standard errors and confidence
intervals for the breakpoint locations. Where the step-change engines
model jumps in the level, segmented models kinks in the trend, so
change_in is "slope" and the fitted broken line is stored in
the fitted column for autoplot(show_fit = TRUE).
segmented_wrapper( x, npsi = 1, conf_level = 0.95, seed = NULL, data = NULL, seg_z = NULL, family = c("gaussian", "poisson", "binomial"), ... )segmented_wrapper( x, npsi = 1, conf_level = 0.95, seed = NULL, data = NULL, seg_z = NULL, family = c("gaussian", "poisson", "binomial"), ... )
x |
A numeric vector (a line in time is segmented), or a model
formula (supply |
npsi |
Number of breakpoints to estimate. Defaults to |
conf_level |
Confidence level for breakpoint intervals. Defaults to
|
seed |
Optional seed (the estimator uses bootstrap restarting). The
seed is scoped to this call: |
data |
A data frame, for formula input. |
seg_z |
For formula input, the covariate whose relationship with
the response breaks: its name, or a one-sided formula ( |
family |
|
... |
Additional arguments passed to |
Called with a numeric vector it segments a line in time. Called with a
formula and data it does what the engine exists for: breakpoints
in the relationship between the response and a covariate,
seg_z. The result is then ordered by that covariate, which
becomes its index, so tidy()'s cp_index and the plot speak
in the covariate's units, and psi, psi_lower and
psi_upper give the breakpoints on that scale exactly.
A ggcpt object with ci_lower/ci_upper columns
and the fitted broken line in $data$fitted. Breakpoints are
rounded to the nearest index; for a continuous fit the reported location
is the kink itself. A constant series has no kink and returns an empty
result, rather than the arbitrary breakpoint a singular fit would give.
Formula input adds psi, psi_lower and psi_upper
(the breakpoints on the covariate's scale) and a $coefficients
table with the slope of seg_z in each segment.
Muggeo VM (2003). “Estimating regression models with unknown break-points.” Statistics in Medicine, 22(19), 3055–3071.
Muggeo VM (2008). “segmented: An R package to fit regression models with broken-line relationships.” R News, 8(1), 20–25.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) y <- cumsum(c(rep(0.5, 100), rep(-0.3, 100))) + rnorm(200) res <- segmented_wrapper(y, npsi = 1) res$changepoints ggplot2::autoplot(res, show_fit = TRUE, show_ci = TRUE) # A breakpoint in a dose-response relationship d <- data.frame(dose = runif(150, 0, 10)) d$response <- 2 + 0.8 * pmin(d$dose, 6) + rnorm(150, 0, 0.4) fit <- segmented_wrapper(response ~ dose, data = d) fit$changepoints[, c("cp", "psi", "psi_lower", "psi_upper")]set.seed(2026) y <- cumsum(c(rep(0.5, 100), rep(-0.3, 100))) + rnorm(200) res <- segmented_wrapper(y, npsi = 1) res$changepoints ggplot2::autoplot(res, show_fit = TRUE, show_ci = TRUE) # A breakpoint in a dose-response relationship d <- data.frame(dose = runif(150, 0, 10)) d$response <- 2 + 0.8 * pmin(d$dose, 6) + rnorm(150, 0, 0.4) fit <- segmented_wrapper(response ~ dose, data = d) fit$changepoints[, c("cp", "psi", "psi_lower", "psi_upper")]
The classic Donoho-Johnstone blocks test signal with known changepoints.
signal_blocks(n = 2048, seed = NULL)signal_blocks(n = 2048, seed = NULL)
n |
Length of the signal. Defaults to 2048. |
seed |
Optional seed. The seed is scoped to this call:
|
A tibble with columns index and value. The true_changepoints
attribute contains the known changepoint locations.
Donoho, D. L. and Johnstone, I. M. (1994). Ideal spatial adaptation by wavelet shrinkage. Biometrika, 81(3), 425-455.
Other test signals:
cpt_simulate(),
signal_fms(),
signal_mix(),
signal_stairs(),
signal_teeth()
x <- signal_blocks(seed = 2026) attr(x, "true_changepoints") # PELT recovers all eleven Donoho-Johnstone jumps cpt_detect(x$value, method = "pelt")$changepoints$cpx <- signal_blocks(seed = 2026) attr(x, "true_changepoints") # PELT recovers all eleven Donoho-Johnstone jumps cpt_detect(x$value, method = "pelt")$changepoints$cp
A piecewise-constant test signal from the WBS/NOT literature.
signal_fms(n = 2000, seed = NULL)signal_fms(n = 2000, seed = NULL)
n |
Length of the signal. Defaults to 2000. |
seed |
Optional seed. The seed is scoped to this call:
|
A tibble with columns index and value.
Other test signals:
cpt_simulate(),
signal_blocks(),
signal_mix(),
signal_stairs(),
signal_teeth()
x <- signal_fms(seed = 2026) cp <- cpt_detect(x$value, method = "pelt")$changepoints$cp # the smallest jumps (0.5, against noise sd 0.5) are the ones missed cpt_metrics(cp, attr(x, "true_changepoints"), n = nrow(x))$coveringx <- signal_fms(seed = 2026) cp <- cpt_detect(x$value, method = "pelt")$changepoints$cp # the smallest jumps (0.5, against noise sd 0.5) are the ones missed cpt_metrics(cp, attr(x, "true_changepoints"), n = nrow(x))$covering
A piecewise-constant/linear signal from the literature.
signal_mix(n = 2000, seed = NULL)signal_mix(n = 2000, seed = NULL)
n |
Length of the signal. Defaults to 2000. |
seed |
Optional seed. The seed is scoped to this call:
|
A tibble with columns index and value.
Other test signals:
cpt_simulate(),
signal_blocks(),
signal_fms(),
signal_stairs(),
signal_teeth()
x <- signal_mix(seed = 2026) attr(x, "true_changepoints") # the linear ramps are not level shifts, so a mean-change detector puts # changepoints inside them rather than at the segment joins cpt_detect(x$value, method = "pelt")$changepoints$cpx <- signal_mix(seed = 2026) attr(x, "true_changepoints") # the linear ramps are not level shifts, so a mean-change detector puts # changepoints inside them rather than at the segment joins cpt_detect(x$value, method = "pelt")$changepoints$cp
A monotonically stepping signal (staircase).
signal_stairs(n = 2000, seed = NULL)signal_stairs(n = 2000, seed = NULL)
n |
Length of the signal. Defaults to 2000. |
seed |
Optional seed. The seed is scoped to this call:
|
A tibble with columns index and value.
Other test signals:
cpt_simulate(),
signal_blocks(),
signal_fms(),
signal_mix(),
signal_teeth()
x <- signal_stairs(n = 500, seed = 2026) attr(x, "true_changepoints") # ten steps, so nine changes cpt_detect(x$value, method = "pelt")$changepoints$cpx <- signal_stairs(n = 500, seed = 2026) attr(x, "true_changepoints") # ten steps, so nine changes cpt_detect(x$value, method = "pelt")$changepoints$cp
A piecewise-constant signal with regularly spaced changepoints.
signal_teeth(n = 2000, seed = NULL)signal_teeth(n = 2000, seed = NULL)
n |
Length of the signal. Defaults to 2000. |
seed |
Optional seed. The seed is scoped to this call:
|
A tibble with columns index and value.
Other test signals:
cpt_simulate(),
signal_blocks(),
signal_fms(),
signal_mix(),
signal_stairs()
x <- signal_teeth(n = 600, seed = 2026) attr(x, "true_changepoints") # a change every 100 observations cpt_detect(x$value, method = "pelt")$changepoints$cpx <- signal_teeth(n = 600, seed = 2026) attr(x, "true_changepoints") # a change every 100 observations cpt_detect(x$value, method = "pelt")$changepoints$cp
Wraps stepR::stepFit() for the Simultaneous MUltiscale Changepoint
Estimator (SMUCE) of Frick, Munk and Sieling (2014) and its heterogeneous
extension HSMUCE (Pein, Sieling and Munk, 2017). SMUCE estimates a step
function subject to a simultaneous multiscale test at level alpha;
the level bounds the probability of over-estimating the number of
changepoints, and the fit delivers confidence intervals for every
changepoint location, which populate the ci_lower/ci_upper
columns of the result and render via autoplot(show_ci = TRUE) or
geom_cpt_ci().
smuce_wrapper( x, alpha = 0.5, family = c("gauss", "hsmuce", "poisson", "binomial"), ... )smuce_wrapper( x, alpha = 0.5, family = c("gauss", "hsmuce", "poisson", "binomial"), ... )
x |
A numeric vector. |
alpha |
Significance level of the multiscale test in |
family |
Noise model: |
... |
Additional arguments passed to |
A ggcpt object. The changepoints tibble carries
ci_lower/ci_upper (confidence interval for each
changepoint location) and the data tibble carries the SMUCE step
fit in its fitted column.
Frick K, Munk A, Sieling H (2014). “Multiscale change point inference.” Journal of the Royal Statistical Society: Series B, 76(3), 495–580.
Pein F, Sieling H, Munk A (2017). “Heterogeneous change point inference.” Journal of the Royal Statistical Society: Series B, 79(4), 1207–1227.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) x <- c(rnorm(100), rnorm(100, 3)) res <- smuce_wrapper(x) res$changepoints ggplot2::autoplot(res, show_ci = TRUE)set.seed(2026) x <- c(rnorm(100), rnorm(100, 3)) res <- smuce_wrapper(x) res$changepoints ggplot2::autoplot(res, show_ci = TRUE)
Wraps SNSeg::SNSeg_Uni() (Zhao, Jiang and Shao, 2022):
self-normalised segmentation with nested local windows. Self-normalisation
avoids estimating the long-run variance, is robust to temporal dependence,
and detects changes in general parameters (mean, variance, quantiles,
autocorrelation, or bivariate correlation) within one framework.
sn_wrapper( x, parameter = c("mean", "variance", "acf", "bivcor"), confidence = 0.9, grid_size = NULL, ... )sn_wrapper( x, parameter = c("mean", "variance", "acf", "bivcor"), confidence = 0.9, grid_size = NULL, ... )
x |
A numeric vector (or a two-column matrix for
|
parameter |
Which parameter to test for changes: |
confidence |
Confidence level of the self-normalised test, one of
0.9, 0.95, 0.99, 0.995 or 0.999. Defaults to |
grid_size |
Grid size controlling the local-window sweep; when
|
... |
Additional arguments passed to |
A ggcpt object. About 20 observations are needed for the
nested local windows at the default grid_size; a constant series
returns an empty result rather than an engine error.
Zhao Z, Jiang F, Shao X (2022). “Segmenting time series via self-normalisation.” Journal of the Royal Statistical Society: Series B, 84(5), 1699–1725.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) res <- sn_wrapper(c(rnorm(150), rnorm(150, 3))) res$changepointsset.seed(2026) res <- sn_wrapper(c(rnorm(150), rnorm(150, 3))) res$changepoints
Runs changepoint detection inside the ggplot pipeline. Useful for
quick exploration: ggplot(df, aes(t, y)) + geom_line() +
stat_changepoint(method = "pelt"). Draws vertical lines at detected
changepoint locations.
stat_changepoint( mapping = NULL, data = NULL, geom = "vline", position = "identity", ..., method = "pelt", change_in = "mean", na.rm = FALSE, show.legend = NA )stat_changepoint( mapping = NULL, data = NULL, geom = "vline", position = "identity", ..., method = "pelt", change_in = "mean", na.rm = FALSE, show.legend = NA )
mapping |
Aesthetic mappings. |
data |
A data frame. |
geom |
The geometric object to use (default: |
position |
Position adjustment. |
... |
Other arguments passed to the geom. |
method |
Detection method (passed to |
change_in |
What to detect change in (passed to |
na.rm |
If |
show.legend |
Whether to show legend. |
A ggplot layer.
Other ggplot2 layers:
geom_changepoint(),
geom_cpt_ci(),
geom_cpt_event(),
geom_cpt_label(),
geom_cpt_region(),
geom_cpt_segment(),
ggchangepoint-ggproto,
stat_cpt_region()
library(ggplot2) set.seed(2026) d <- data.frame(t = 1:100, y = c(rnorm(50), rnorm(50, 4))) ggplot(d, aes(t, y)) + geom_line() + stat_changepoint(method = "pelt", colour = "blue")library(ggplot2) set.seed(2026) d <- data.frame(t = 1:100, y = c(rnorm(50), rnorm(50, 4))) ggplot(d, aes(t, y)) + geom_line() + stat_changepoint(method = "pelt", colour = "blue")
The region twin of stat_changepoint(): runs detection on
the layer's own x/y and draws what the method returns as
an interval, so
ggplot(d, aes(t, y)) + geom_line() + stat_cpt_region() is the
whole plot. Narrowest Significance Pursuit (method = "nsp", the
default) returns regions, each containing a changepoint at a global
significance level; a method with location intervals ("smuce",
"strucchange", "segmented", ...) draws those instead.
stat_cpt_region( mapping = NULL, data = NULL, geom = GeomCptRegion, position = "identity", ..., method = "nsp", na.rm = FALSE, show.legend = NA )stat_cpt_region( mapping = NULL, data = NULL, geom = GeomCptRegion, position = "identity", ..., method = "nsp", na.rm = FALSE, show.legend = NA )
mapping |
Aesthetic mappings. |
data |
A data frame. |
geom |
The geom to draw with. Defaults to
|
position |
Position adjustment. |
... |
Further arguments: those the detector takes (for example
|
method |
Detection method: |
na.rm |
If |
show.legend |
Whether to show legend. |
A ggplot layer.
Other ggplot2 layers:
geom_changepoint(),
geom_cpt_ci(),
geom_cpt_event(),
geom_cpt_label(),
geom_cpt_region(),
geom_cpt_segment(),
ggchangepoint-ggproto,
stat_changepoint()
library(ggplot2) set.seed(2026) d <- data.frame(t = 1:200, y = c(rnorm(100), rnorm(100, 2))) ggplot(d, aes(t, y)) + stat_cpt_region(seed = 1) + geom_line()library(ggplot2) set.seed(2026) d <- data.frame(t = 1:200, y = c(rnorm(100), rnorm(100, 2))) ggplot(d, aes(t, y)) + stat_cpt_region(seed = 1) + geom_line()
Wraps strucchange::breakpoints() (Zeileis et al., 2002), the
dynamic-programming implementation of the Bai and Perron (1998, 2003)
multiple structural break estimator. Called with a bare numeric vector it
dates mean shifts (y ~ 1); called with a formula and data it dates
breaks in arbitrary regression coefficients. Break-date confidence
intervals from confint() populate ci_lower/ci_upper
and render via autoplot(show_ci = TRUE).
strucchange_wrapper( x, data = NULL, breaks = NULL, h = 0.15, conf_level = 0.95, ... )strucchange_wrapper( x, data = NULL, breaks = NULL, h = 0.15, conf_level = 0.95, ... )
x |
A numeric vector (mean-shift mode), or a model formula
(regression mode; supply |
data |
Optional data frame for formula input. |
breaks |
Maximum number of breaks; when |
h |
Minimal segment size, as a fraction of the sample size (or an
integer count). Defaults to |
conf_level |
Confidence level for the break-date intervals. Defaults
to |
... |
Additional arguments passed to
|
A ggcpt object with ci_lower/ci_upper columns
on the changepoints tibble.
$fit is the breakpoints object itself, and that object is
quadratic in the series length: it keeps RSS.triang, the triangular
table of segment residual sums of squares, which is what lets
strucchange return the optimal segmentation for any number
of breaks without refitting. Measured here, the whole result is about
1.7 MB at n = 200, 5.9 MB at n = 400 and 22.6 MB at
n = 800, roughly four times larger each time the series doubles,
and that one table outweighs everything else in the fit put together, by a
margin that widens as the series grows. A single fit is not a problem; a
few hundred of them are, so when running this engine over a panel with
cpt_batch() keep what you need
(res$changepoints) rather than the whole list of results. No other
engine here behaves this way: the median result across the others is
under ten times the size of the series it was given.
Bai J, Perron P (2003). “Computation and analysis of multiple structural change models.” Journal of Applied Econometrics, 18(1), 1–22.
Zeileis A, Leisch F, Hornik K, Kleiber C (2002). “strucchange: An R package for testing for structural change in linear regression models.” Journal of Statistical Software, 7(2), 1–38.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) res <- strucchange_wrapper(c(rnorm(100), rnorm(100, 3))) res$changepointsset.seed(2026) res <- strucchange_wrapper(c(rnorm(100), rnorm(100, 3))) res$changepoints
Provides a human-readable digest of a changepoint detection result,
including the segment table with levels and lengths (the level is the
segment mean whatever 'change_in' says; see new_ggcpt),
total cost,
penalty, and runtime.
## S3 method for class 'ggcpt' summary(object, ...) ## S3 method for class 'summary.ggcpt' print(x, ...)## S3 method for class 'ggcpt' summary(object, ...) ## S3 method for class 'summary.ggcpt' print(x, ...)
object |
A |
... |
Additional arguments (ignored). |
x |
A |
A list with class summary.ggcpt containing the summary.
set.seed(2026) summary(cpt_detect(c(rnorm(60), rnorm(60, 3)), method = "pelt"))set.seed(2026) summary(cpt_detect(c(rnorm(60), rnorm(60, 3)), method = "pelt"))
Wraps ChangePointTaylor::change_point_analyzer(): the
bootstrap-and-recursion procedure of Wayne Taylor that the quality-control
and Six Sigma community uses as its default. Each candidate is scored by
the bootstrap probability that a change occurred there, which gives a
confidence level per changepoint and a confidence interval for its
location, both carried onto the result.
taylor_wrapper( x, n_bootstraps = 1000, min_candidate_conf = 0.5, min_conf = 0.9, conf_level = 0.95, seed = NULL )taylor_wrapper( x, n_bootstraps = 1000, min_candidate_conf = 0.5, min_conf = 0.9, conf_level = 0.95, seed = NULL )
x |
A numeric vector. |
n_bootstraps |
Bootstrap samples per candidate. Defaults to
|
min_candidate_conf |
Minimum confidence for a candidate to be
considered, between 0.3 and 1. Defaults to |
min_conf |
Minimum confidence for a changepoint to be reported,
between 0.5 and 1. Defaults to |
conf_level |
Confidence level of the reported location intervals,
between 0.9 and 0.999 (the engine's range). Defaults to |
seed |
Optional seed (the procedure is bootstrap-based). The seed is
scoped to this call: |
A ggcpt object with ci_lower/ci_upper (so
autoplot(show_ci = TRUE) works) and a confidence column.
This engine is written for the series lengths quality control sees
(hundreds to low thousands), and it does not scale. At
with the default n_bootstraps = 1000 it runs for minutes, and
more importantly it runs where R cannot look: a setTimeLimit() of
45 seconds was still not honoured after 170, and one of 125 seconds after
200, so the call had to be killed from outside the session. R checks
elapsed-time limits and keyboard interrupts at the same points, which
means Ctrl-C will not stop it either.
So size the call before starting it rather than after. n_bootstraps
is the knob (the cost is roughly linear in it), and the
“Benchmarks” article lists the methods that do scale to long
series. That page is web-only, because the sweep behind it takes
over twenty minutes: it is published at
https://pursuitofdatascience.github.io/ggchangepoint/articles/benchmarks.html
rather than built into the package, so vignette() will not
find it.
Taylor WA (2000). Change-Point Analysis: A Powerful New Tool for Detecting Changes. Taylor Enterprises, Libertyville, Illinois.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) taylor_wrapper(c(rnorm(60), rnorm(60, 3)), n_bootstraps = 200, seed = 1)set.seed(2026) taylor_wrapper(c(rnorm(60), rnorm(60, 3)), n_bootstraps = 200, seed = 1)
Wraps the breakfast package for Tail-Greedy Unbalanced-Haar
detection, with information-criterion model selection.
tguh_wrapper(x, ...)tguh_wrapper(x, ...)
x |
A numeric vector. |
... |
Additional arguments passed to |
A ggcpt object.
Fryzlewicz P (2018). “Tail-Greedy Bottom-Up Data Decompositions and Fast Multiple Change-Point Detection.” The Annals of Statistics, 46(6B), 3390–3421.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) res <- tguh_wrapper(c(rnorm(60), rnorm(60, 4))) res$changepoints res$penalty$typeset.seed(2026) res <- tguh_wrapper(c(rnorm(60), rnorm(60, 4))) res$changepoints res$penalty$type
A minimal, publication-ready ggplot2 theme for changepoint plots.
theme_ggcpt(base_size = 11, base_family = "")theme_ggcpt(base_size = 11, base_family = "")
base_size |
Base font size. Defaults to 11. |
base_family |
Base font family. Defaults to "". |
A ggplot2 theme object.
Other accessibility scales:
scale_colour_cpt(),
scale_fill_cpt_label()
library(ggplot2) ggplot(mtcars, aes(wt, mpg)) + geom_point() + theme_ggcpt()library(ggplot2) ggplot(mtcars, aes(wt, mpg)) + geom_point() + theme_ggcpt()
Returns the changepoints tibble (one row per changepoint), or the coefficients of every segment.
## S3 method for class 'ggcpt' tidy(x, what = c("changepoints", "coefficients"), conf_level = 0.95, ...)## S3 method for class 'ggcpt' tidy(x, what = c("changepoints", "coefficients"), conf_level = 0.95, ...)
x |
A |
what |
|
conf_level |
Confidence level for the coefficient intervals. |
... |
Additional arguments (ignored). |
A tibble. For "changepoints": columns cp,
cp_value, and any method-specific columns. For
"coefficients": segment, start, end,
term, estimate, std_error, conf_low,
conf_high (plus coordinate for a multivariate result).
set.seed(1) fit <- cpt_detect(c(rnorm(80), rnorm(80, 3)), method = "pelt") tidy(fit) tidy(fit, "coefficients")set.seed(1) fit <- cpt_detect(c(rnorm(80), rnorm(80, 3)), method = "pelt") tidy(fit) tidy(fit, "coefficients")
Wraps the three single-change tests that hydrology and climatology use as
their standard vocabulary, from the trend package. All three test
: no change against a single change in the mean, differing in how
they measure it:
"pettitt"a rank-based (Mann-Whitney) statistic, distribution-free and robust to outliers.
"buishand"the Buishand range test, based on rescaled adjusted partial sums; assumes normality.
"snht"the standard normal homogeneity test of Alexandersson, the reference method for detecting inhomogeneities in climate records.
Each reports a location and a p-value, and, unlike most engines here, that p-value is valid, because the location was not chosen from a larger model search.
trend_wrapper(x, test = c("pettitt", "buishand", "snht"), alpha = 0.05, ...)trend_wrapper(x, test = c("pettitt", "buishand", "snht"), alpha = 0.05, ...)
x |
A numeric vector. |
test |
Which test to run. Defaults to |
alpha |
Significance level below which the changepoint is reported.
Defaults to |
... |
Additional arguments passed to the trend function. |
A ggcpt object with the test's p_value and
statistic on the changepoints tibble. The per-position test
statistic is available through cpt_statistic().
Pettitt AN (1979). “A non-parametric approach to the change-point problem.” Journal of the Royal Statistical Society: Series C, 28(2), 126–135. doi:10.2307/2346729.
Buishand TA (1982). “Some methods for testing the homogeneity of rainfall records.” Journal of Hydrology, 58(1–2), 11–27. doi:10.1016/0022-1694(82)90066-X.
Alexandersson H (1986). “A homogeneity test applied to precipitation data.” Journal of Climatology, 6(6), 661–675. doi:10.1002/joc.3370060607.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) x <- c(rnorm(60), rnorm(60, 2)) trend_wrapper(x, test = "pettitt") trend_wrapper(x, test = "snht")set.seed(2026) x <- c(rnorm(60), rnorm(60, 2)) trend_wrapper(x, test = "pettitt") trend_wrapper(x, test = "snht")
Wraps changepoints::CV.search.DP.VAR1() (Wang, Yu, Rinaldo and
Willett): dynamic programming with an penalty for changes in
the transition matrix of a vector autoregression, with the two tuning
parameters chosen by cross-validation. The change here is in the
dynamics (how the series predicts itself), not in the level, so it
is invisible to every mean-change engine in the package.
var_wrapper(x, gamma_set = NULL, lambda_set = NULL, delta = NULL, ...)var_wrapper(x, gamma_set = NULL, lambda_set = NULL, delta = NULL, ...)
x |
A numeric matrix or data frame, rows as time points. |
gamma_set |
Candidate values of the |
lambda_set |
Candidate lasso penalties. Defaults to
|
delta |
Minimum spacing. Defaults to |
... |
Additional arguments passed to the engine. |
A ggcpt object with change_in = "regression". The
engine searches every other observation, so a location is resolved to
within two; each is reported as the last observation before the
change, the package convention, rather than the engine's own index,
which sits one or two earlier.
Wang D, Yu Y, Rinaldo A, Willett R (2019). “Localizing changes in high-dimensional vector autoregressive processes.” arXiv preprint arXiv:1909.06359. doi:10.48550/arXiv.1909.06359.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
wbs2_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) p <- 3 step <- function(n, a) { Y <- matrix(0, n, p) for (i in 2:n) Y[i, ] <- a * Y[i - 1, ] + stats::rnorm(p) Y } var_wrapper(rbind(step(50, 0.1), step(50, 0.8)), gamma_set = c(1, 10), lambda_set = c(0.1, 1))set.seed(2026) p <- 3 step <- function(n, a) { Y <- matrix(0, n, p) for (i in 2:n) Y[i, ] <- a * Y[i - 1, ] + stats::rnorm(p) Y } var_wrapper(rbind(step(50, 0.1), step(50, 0.8)), gamma_set = c(1, 10), lambda_set = c(0.1, 1))
Wraps the wbs package for randomised changepoint detection via
Wild Binary Segmentation.
wbs_wrapper(x, n_intervals = 5000, threshold = NULL, seed = NULL, ...)wbs_wrapper(x, n_intervals = 5000, threshold = NULL, seed = NULL, ...)
x |
A numeric vector. |
n_intervals |
Number of random intervals. Defaults to |
threshold |
Manual threshold for detection. If |
seed |
Optional seed for reproducibility. The seed is scoped to this
call: |
... |
Additional arguments passed to |
A ggcpt object.
Fryzlewicz P (2014). “Wild Binary Segmentation for Multiple Change-Point Detection.” The Annals of Statistics, 42(6), 2243–2281. doi:10.1214/14-AOS1245.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbsts_wrapper()
set.seed(2026) res <- wbs_wrapper(c(rnorm(60), rnorm(60, 4)), n_intervals = 200) res$changepoints res$penalty$type # sSIC selection, because `threshold` was not suppliedset.seed(2026) res <- wbs_wrapper(c(rnorm(60), rnorm(60, 4)), n_intervals = 200) res$changepoints res$penalty$type # sSIC selection, because `threshold` was not supplied
Wraps the breakfast package's WBS2 solution path with
steepest-drop-to-low-levels (SDLL) model selection.
wbs2_wrapper(x, ...)wbs2_wrapper(x, ...)
x |
A numeric vector. |
... |
Additional arguments passed to |
A ggcpt object.
This engine is not reproducible call to call within an R
session, and no argument here can make it so. On a 200-point series with
one change at 100, repeated identical calls (same input,
set.seed() re-run beforehand so that .Random.seed is
byte-identical on entry) return a last changepoint of either 183 or
188, roughly evenly split. The variation is therefore not driven by R's
random number stream, which is why this wrapper has no seed
argument to offer: there is no stream to pin.
It is upstream, not in this package. Calling
breakfast::breakfast(x, solution.path = "wbs2",
model.selection = "sdll") directly (breakfast 2.5) reproduces it
exactly. A fresh R session is deterministic (five separate
sessions agreed), so what varies is state the engine carries between
calls.
In practice this is rare, and needs a series whose model selection sits
near a tie. Measured over eight other series with three identical calls
each, wbs2 was stable on all eight; the flip above reproduces
only on that one configuration. tguh, which uses the same
package, was stable throughout, as were the other 35 of the 50 wired
methods this experiment covered (the rest need an engine that was not
installed when it was run). If you need a segmentation you can reproduce
exactly, take the result of the first call in a session, or use an
engine with a seed argument (cpt_methods()
reports which wrappers have one).
Fryzlewicz P (2020). “Detecting Multiple Change-Point Features via Narrowest-Over-Threshold.” Journal of the Royal Statistical Society Series B, 82(5), 1377–1418.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs_wrapper(),
wbsts_wrapper()
set.seed(2026) res <- wbs2_wrapper(c(rnorm(60), rnorm(60, 4))) res$changepointsset.seed(2026) res <- wbs2_wrapper(c(rnorm(60), rnorm(60, 4))) res$changepoints
Wraps wbsts::wbs.lsw() (Korkas and Fryzlewicz): wild binary
segmentation applied to the locally stationary wavelet spectrum, so it
detects changes in the second-order structure (variance and
autocovariance) of a nonstationary series. Where wbs looks for
jumps in the level, this looks for jumps in how the series behaves.
wbsts_wrapper( x, n_intervals = 0, cstar = 0.75, lambda = 0.75, scales = NULL, seed = NULL, ... )wbsts_wrapper( x, n_intervals = 0, cstar = 0.75, lambda = 0.75, scales = NULL, seed = NULL, ... )
x |
A numeric vector. |
n_intervals |
Number of random intervals ( |
cstar |
The unbalancedness parameter |
lambda |
How many wavelet scales are used when |
scales |
Wavelet scales to use: at least two different whole
numbers from 1 to |
seed |
Optional seed. The seed is scoped to this call:
|
... |
Additional arguments passed to |
A ggcpt object with change_in = "var".
Korkas KK, Fryzlewicz P (2017). “Multiple change-point detection for non-stationary time series using wild binary segmentation.” Statistica Sinica, 27(1), 287–311. doi:10.5705/ss.202015.0262.
Other changepoint engines:
bcp_wrapper(),
beast_wrapper(),
bfast_wrapper(),
binsegrcpp_wrapper(),
bocpd_wrapper(),
cpm_wrapper(),
cpop_wrapper(),
cpt_wrapper(),
decafs_wrapper(),
ecp_wrapper(),
envcpt_wrapper(),
esac_wrapper(),
fabisearch_wrapper(),
fastcpd_wrapper(),
fcov_wrapper(),
fmean_wrapper(),
fpop_wrapper(),
geomcp_wrapper(),
hdcov_wrapper(),
hdreg_wrapper(),
idetect_wrapper(),
inspect_wrapper(),
kcp_wrapper(),
kwc_wrapper(),
mcp_wrapper(),
mosum_wrapper(),
network_wrapper(),
not_wrapper(),
npmojo_wrapper(),
nsp_wrapper(),
ocd_wrapper(),
pilliat_wrapper(),
segmented_wrapper(),
smuce_wrapper(),
sn_wrapper(),
strucchange_wrapper(),
taylor_wrapper(),
tguh_wrapper(),
trend_wrapper(),
var_wrapper(),
wbs2_wrapper(),
wbs_wrapper()
set.seed(2026) y <- c(as.numeric(stats::arima.sim(list(ar = 0.1), 250)), as.numeric(stats::arima.sim(list(ar = 0.9), 250))) wbsts_wrapper(y)set.seed(2026) y <- c(as.numeric(stats::arima.sim(list(ar = 0.1), 250)), as.numeric(stats::arima.sim(list(ar = 0.9), 250))) wbsts_wrapper(y)