The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

The ggchangepoint Feature Tour: A Complete Map of the Package Surface

Youzhi Yu
University of Chicago

Abstract

ggchangepoint provides a unified, tidy, ggplot2-native interface to changepoint detection in R: one dispatcher (cpt_detect()) covering 31 methods across six methodological families, one result class (ggcpt) with a stable tidy contract, and one visualisation entry point (autoplot()) that draws everything a method reports — including confidence intervals and posterior probabilities (Wickham 2016; Robinson 2017). This vignette is the feature tour: it visits every exported function in the package at the point where it belongs in the workflow, so a reader can map the full surface in one sitting. The companion vignettes develop the methodology in depth (vignette("introduction")) and treat method comparison and evaluation (vignette("comparison")).

set.seed(2026)
x <- c(rnorm(100, 0, 1), rnorm(100, 6, 1))    # one mean shift at t = 100
x3 <- c(rnorm(100), rnorm(100, 4), rnorm(100, 1))  # shifts at 100, 200

The result object and its methods

Every detector returns a ggcpt object: a list carrying the tidy changepoints tibble (cp = last index of the left segment, cp_value = series value there, plus any method-specific columns), a segments table, the data, the raw engine fit, and metadata (method, change_in, penalty, convention, runtime). new_ggcpt() is the low-level constructor and is_ggcpt() the class test; most users never call either directly.

res <- cpt_detect(x, method = "pelt", change_in = "mean")
is_ggcpt(res)
#> [1] TRUE
print(res)
#> ggcpt (changepoint detection result)
#>   Method:          pelt 
#>   Change in:       mean 
#>   Changepoints found: 1 
#>   CP convention:   left 
#>   Penalty:         MBIC 
#>   Series length:   200 
#> 
#> Changepoints:
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1   100    0.369
manual <- new_ggcpt(
  changepoints = tibble::tibble(cp = 100L, cp_value = x[100]),
  data = tibble::tibble(index = seq_along(x), value = x),
  method = "manual"
)
is_ggcpt(manual)
#> [1] TRUE

The broom verbs give one row per changepoint (tidy()), a one-row model summary (glance()), and the data augmented with segment ids, fitted levels, residuals, and a changepoint flag (augment()):

tidy(res)
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1   100    0.369
glance(res)
#> # A tibble: 1 × 9
#>       n n_changepoints method change_in penalty_type penalty_value cp_convention
#>   <int>          <int> <chr>  <chr>     <chr>                <dbl> <chr>        
#> 1   200              1 pelt   mean      MBIC                    NA left         
#> # ℹ 2 more variables: total_cost <dbl>, runtime <dbl>
head(augment(res))
#> # A tibble: 6 × 6
#>   index   value seg_id .fitted  .resid is_changepoint
#>   <int>   <dbl>  <int>   <dbl>   <dbl> <lgl>         
#> 1     1  0.521       1 -0.0980  0.619  FALSE         
#> 2     2 -1.08        1 -0.0980 -0.982  FALSE         
#> 3     3  0.139       1 -0.0980  0.237  FALSE         
#> 4     4 -0.0847      1 -0.0980  0.0133 FALSE         
#> 5     5 -0.667       1 -0.0980 -0.569  FALSE         
#> 6     6 -2.52        1 -0.0980 -2.42   FALSE

The remaining S3 surface: a human-readable digest, tibble/data-frame coercion, a one-line format, and a base-plot() fallback that delegates to autoplot().

summary(res)
#> ggcpt Summary
#>   Method:                   pelt 
#>   Change in:                mean 
#>   Changepoints found:       1 
#>   CP convention:            left 
#>   Series length:            200 
#>   Penalty:                  MBIC 
#>   Runtime (seconds):        0.008 
#> 
#> Segments:
#> # A tibble: 2 × 5
#>   seg_id start   end     n param_estimate
#>    <int> <int> <int> <int>          <dbl>
#> 1      1     1   100   100        -0.0980
#> 2      2   101   200   100         6.12  
#> 
#> Changepoints:
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1   100    0.369
as_tibble(res)
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1   100    0.369
head(as.data.frame(res))
#>    cp  cp_value
#> 1 100 0.3694259
format(res)
#> [1] "ggcpt [pelt] 1 changepoint(s) on 200 observations"
plot(res)

ggchangepoint feature tour plot

Unified detection

cpt_detect() is the recommended entry point: pick a method, say what the change is in (change_in = "mean", "var", "meanvar", "slope", or "distribution"), and optionally set a penalty. Incompatible method/change_in combinations error — they are never silently substituted.

cpt_detect(x, method = "binseg", change_in = "mean")
#> ggcpt (changepoint detection result)
#>   Method:          binseg 
#>   Change in:       mean 
#>   Changepoints found: 1 
#>   CP convention:   left 
#>   Penalty:         MBIC 
#>   Series length:   200 
#> 
#> Changepoints:
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1   100    0.369

Anything else in ... reaches the underlying wrapper, and takes precedence over the value the dispatcher would otherwise derive from change_in — here the NOT contrast is set directly rather than inherited:

tidy(cpt_detect(x, method = "not", contrast = "pcwsLinMean"))
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1   100    0.369

cpt_methods() is the live capability table: every method the package knows, its engine package, what it can detect, and whether the engine is installed. Four rows carry status "planned" rather than "available": their engines (gfpop, robseg, FOCuS, hdbinseg) are not on CRAN, so they are documented as future work and are not wired to cpt_detect().

print(cpt_methods(), n = Inf)
#> # A tibble: 35 × 6
#>    method      change_in                  engine status target_release installed
#>    <chr>       <chr>                      <chr>  <chr>  <chr>          <lgl>    
#>  1 pelt        mean, var, meanvar         chang… avail… <NA>           TRUE     
#>  2 binseg      mean, var, meanvar         chang… avail… <NA>           TRUE     
#>  3 segneigh    mean, var, meanvar         chang… avail… <NA>           TRUE     
#>  4 amoc        mean, var, meanvar         chang… avail… <NA>           TRUE     
#>  5 np          distribution               chang… avail… <NA>           TRUE     
#>  6 ecp         distribution (multivariat… ecp    avail… <NA>           TRUE     
#>  7 fpop        mean                       fpop   avail… <NA>           TRUE     
#>  8 wbs         mean                       wbs    avail… <NA>           TRUE     
#>  9 wbs2        mean                       break… avail… <NA>           TRUE     
#> 10 not         mean, var, slope           not    avail… <NA>           TRUE     
#> 11 mosum       mean                       mosum  avail… <NA>           TRUE     
#> 12 idetect     mean                       IDete… avail… <NA>           TRUE     
#> 13 tguh        mean                       break… avail… <NA>           TRUE     
#> 14 smuce       mean (with CIs)            stepR  avail… <NA>           FALSE    
#> 15 hsmuce      mean (heteroskedastic, wi… stepR  avail… <NA>           FALSE    
#> 16 cpop        slope                      cpop   avail… <NA>           FALSE    
#> 17 bcp         mean (Bayesian)            bcp    avail… <NA>           FALSE    
#> 18 bocpd       mean (Bayesian online)     ocp    avail… <NA>           FALSE    
#> 19 beast       mean/trend (Bayesian)      Rbeast avail… <NA>           FALSE    
#> 20 cpm         distribution (sequential)  cpm    avail… <NA>           FALSE    
#> 21 kcp         running statistics (kerne… kcpRS  avail… <NA>           FALSE    
#> 22 npmojo      distribution (multivariat… CptNo… avail… <NA>           FALSE    
#> 23 decafs      mean (drift + AR noise)    DeCAFS avail… <NA>           FALSE    
#> 24 sn          mean, var, acf, correlati… SNSeg  avail… <NA>           FALSE    
#> 25 inspect     mean (high-dimensional)    Inspe… avail… <NA>           FALSE    
#> 26 ocd         mean (high-dimensional, o… ocd    avail… <NA>           FALSE    
#> 27 geomcp      distribution (multivariat… chang… avail… <NA>           FALSE    
#> 28 strucchange mean, regression (with CI… struc… avail… <NA>           FALSE    
#> 29 segmented   slope (with CIs)           segme… avail… <NA>           FALSE    
#> 30 envcpt      mean/trend vs autocorrela… EnvCpt avail… <NA>           FALSE    
#> 31 fastcpd     mean, var, meanvar, AR/AR… fastc… avail… <NA>           FALSE    
#> 32 gfpop       mean (graph-constrained)   gfpop  plann… when on CRAN   NA       
#> 33 robust      mean (robust loss)         robseg plann… when on CRAN   NA       
#> 34 focus       mean (online)              FOCuS  plann… when on CRAN   NA       
#> 35 sbs         mean (high-dimensional)    hdbin… plann… next release   NA

cpt_penalty() constructs standard penalty values for the engines that take numeric penalties; see its help for the per-engine penalty semantics.

cpt_penalty("BIC", n = 200)
#> [1] 5.298317
cpt_penalty("MBIC", n = 200)
#> [1] 10.59663
cpt_penalty("Manual", value = 10)
#> [1] 10

Engine wrappers

Each engine also has a direct wrapper exposing its native arguments. Every wrapper from 0.2.0 onwards returns a ggcpt object; only the two original wrappers below predate the class and still return a bare tibble.

The classical core (0.1.0)

cpt_wrapper() and ecp_wrapper() are the original interface to the changepoint/changepoint.np (Killick, Fearnhead, and Eckley 2012; Killick and Eckley 2014; Haynes, Fearnhead, and Eckley 2017) and ecp (Matteson and James 2014; James and Matteson 2014) engines; they return bare tibbles for backward compatibility.

cpt_wrapper(x, change_in = "mean", cp_method = "PELT")
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1   100    0.369
ecp_wrapper(x, algorithm = "divisive", seed = 1)
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <dbl>    <dbl>
#> 1   101     7.22

The search and pruning wave (0.2.0)

Seven multiscale, randomised, and functional-pruning engines (Fryzlewicz 2014, 2020, 2018; Baranowski, Chen, and Fryzlewicz 2019; Eichinger and Kirch 2018; Anastasiou and Fryzlewicz 2022; Maidstone et al. 2017), one call each:

fpop_wrapper(x, penalty = 2 * log(length(x)))
#> ggcpt (changepoint detection result)
#>   Method:          fpop 
#>   Change in:       mean 
#>   Changepoints found: 1 
#>   CP convention:   left 
#>   Penalty:         Manual = 10.597 
#>   Series length:   200 
#> 
#> Changepoints:
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1   100    0.369
wbs_wrapper(x, n_intervals = 2000, seed = 1)
#> ggcpt (changepoint detection result)
#>   Method:          wbs 
#>   Change in:       mean 
#>   Changepoints found: 1 
#>   CP convention:   left 
#>   Penalty:         sSIC 
#>   Series length:   200 
#> 
#> Changepoints:
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1   100    0.369
wbs2_wrapper(x)
#> ggcpt (changepoint detection result)
#>   Method:          wbs2 
#>   Change in:       mean 
#>   Changepoints found: 1 
#>   CP convention:   left 
#>   Penalty:         SDLL 
#>   Series length:   200 
#> 
#> Changepoints:
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1   100    0.369
not_wrapper(x, contrast = "pcwsConstMean", seed = 1)
#> ggcpt (changepoint detection result)
#>   Method:          not 
#>   Change in:       mean 
#>   Changepoints found: 1 
#>   CP convention:   left 
#>   Penalty:         sSIC 
#>   Series length:   200 
#> 
#> Changepoints:
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1   100    0.369
mosum_wrapper(x)
#> ggcpt (changepoint detection result)
#>   Method:          mosum 
#>   Change in:       mean 
#>   Changepoints found: 1 
#>   CP convention:   left 
#>   Penalty:         threshold = 3.6342 
#>   Series length:   200 
#> 
#> Changepoints:
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1   100    0.369
mosum_wrapper(x3, multiscale = TRUE)
#> ggcpt (changepoint detection result)
#>   Method:          mosum 
#>   Change in:       mean 
#>   Changepoints found: 2 
#>   CP convention:   left 
#>   Penalty:         threshold 
#>   Series length:   300 
#> 
#> Changepoints:
#> # A tibble: 2 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1   100   -0.100
#> 2   200    2.90
idetect_wrapper(x, seed = 1)
#> ggcpt (changepoint detection result)
#>   Method:          idetect 
#>   Change in:       mean 
#>   Changepoints found: 1 
#>   CP convention:   left 
#>   Penalty:         threshold 
#>   Series length:   200 
#> 
#> Changepoints:
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1   100    0.369
tguh_wrapper(x)
#> ggcpt (changepoint detection result)
#>   Method:          tguh 
#>   Change in:       mean 
#>   Changepoints found: 1 
#>   CP convention:   left 
#>   Penalty:         sSIC 
#>   Series length:   200 
#> 
#> Changepoints:
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1   100    0.369

The engine wave (0.4.0)

Multiscale inference with confidence. smuce_wrapper() implements SMUCE (Frick, Munk, and Sieling 2014), which bounds the probability of over-estimating the number of changes at the level alpha and returns a confidence interval for every changepoint location (ci_lower/ci_upper); family = "hsmuce" switches to the heteroskedastic extension HSMUCE (Pein, Sieling, and Munk 2017), which estimates a variance per segment:

res_smuce <- smuce_wrapper(x, alpha = 0.5)
tidy(res_smuce)

Change in slope. cpop_wrapper() performs exact penalised estimation of a continuous piecewise-linear mean (Fearnhead, Maidstone, and Letchford 2019; Fearnhead and Grose 2024):

y_slope <- cumsum(c(rep(0.4, 100), rep(-0.3, 100))) + rnorm(200)
res_cpop <- cpop_wrapper(y_slope)
tidy(res_cpop)

Bayesian detection. bcp_wrapper() implements the Barry–Hartigan product-partition model (Barry and Hartigan 1993; Erdman and Emerson 2007); bocpd_wrapper() runs Bayesian online changepoint detection over the run-length posterior (Adams and MacKay 2007); beast_wrapper() wraps the BEAST Bayesian model-averaging ensemble (K. Zhao et al. 2019). The first and third keep the locations whose posterior probability clears prob_threshold and record it in a posterior_prob column; BOCPD returns the maximum a posteriori changepoint set.

res_bcp <- bcp_wrapper(x, seed = 1)
tidy(res_bcp)
res_bocpd <- bocpd_wrapper(x)
tidy(res_bocpd)
res_beast <- beast_wrapper(x, seed = 1)
tidy(res_beast)

Sequential and kernel nonparametrics. cpm_wrapper() runs distribution-free sequential tests and reports, alongside each estimated location, the detection_time at which a stream monitor would have flagged it (Ross 2015); kcp_wrapper() applies kernel change point analysis to running statistics (mean, variance, autocorrelation, correlation) (Arlot, Celisse, and Harchaoui 2019; Cabrieto et al. 2018); npmojo_wrapper() detects distributional changes under serial dependence (McGonigle and Cho 2025):

tidy(cpm_wrapper(x, cpm_type = "Mann-Whitney"))
tidy(kcp_wrapper(x, running_stat = "mean", nperm = 100, seed = 1))
tidy(npmojo_wrapper(x))

Robustness to drift and dependence. decafs_wrapper() detects abrupt changes when the signal also drifts and the noise is autocorrelated (Romano et al. 2022); sn_wrapper() segments a chosen parameter (mean, variance, autocorrelation, or bivariate correlation) by self-normalisation, avoiding long-run variance estimation entirely (Z. Zhao, Jiang, and Shao 2022); envcpt_wrapper() reports changepoints only when a changepoint model beats the trend and autoregressive alternatives (Beaulieu and Killick 2018):

tidy(decafs_wrapper(x))
tidy(sn_wrapper(x3, parameter = "mean"))
res_env <- envcpt_wrapper(x, models = c("mean", "meancpt", "trendcpt"))
tidy(res_env)
res_env$penalty$type   # criterion and winning model

High-dimensional and multivariate. These wrappers take a matrix or data frame with one row per time point. inspect_wrapper() finds sparse mean changes by projection (Wang and Samworth 2018); ocd_wrapper() monitors a high-dimensional stream online (Chen, Wang, and Samworth 2022); geomcp_wrapper() maps each observation to a distance and an angle and segments both (Grundy, Killick, and Mihaylov 2020); multivariate ecp input flows through cpt_detect() unchanged. The univariate wrappers, by contrast, reject a multi-column argument rather than silently flattening it.

set.seed(1)
X <- cbind(a = c(rnorm(80), rnorm(80, 4)),
           b = c(rnorm(80), rnorm(80, -3)),
           c = rnorm(160))
res_hd <- inspect_wrapper(X)
tidy(res_hd)
# Online detection: the reported locations are declaration times (the change
# plus the detection delay), in a `declared_at` column. Monte Carlo threshold
# calibration makes this the slowest wrapper, so it is shown but not run
# here. It needs at least two coordinates and rejects a univariate series.
res_ocd <- ocd_wrapper(X, mc_reps = 100)
tidy(res_ocd)
tidy(geomcp_wrapper(X))
tidy(cpt_detect(X, method = "ecp", seed = 1))
#> # A tibble: 1 × 2
#>      cp cp_value
#>   <int>    <dbl>
#> 1    80   -0.590

Regression structure. strucchange_wrapper() dates Bai–Perron breaks, either in a bare series or in the coefficients of a formula (Bai and Perron 1998, 2003; Zeileis et al. 2002); segmented_wrapper() fits a continuous broken-line regression, so the change it reports is a kink in the trend rather than a jump in the level (Muggeo 2003, 2008). Both carry a confidence interval for every break:

tidy(strucchange_wrapper(x))
tidy(segmented_wrapper(y_slope, npsi = 1, seed = 1))

The modern PELT family. fastcpd_wrapper() exposes the fastcpd engine, whose family argument covers changes in the mean, the variance, or both, as well as changes in a fitted AR/ARMA/GARCH model (Li and Zhang 2024):

tidy(fastcpd_wrapper(x, family = "mean"))

The penalty path

Rather than guessing one penalty, cpt_crops() computes every optimal segmentation over a penalty interval (the CROPS algorithm, via changepoint (Killick and Eckley 2014)) and returns a ggcpt_path object with its own print(), tidy(), and three autoplot() types:

path <- cpt_crops(x3)
path
#> ggcpt_path (CROPS penalty path)
#>   Change in:       mean 
#>   Penalty range:  [5.704, 57.04]
#>   Series length:   300 
#>   Distinct segmentations: 5 
#> 
#> # A tibble: 5 × 3
#>   penalty n_cpts  cost
#>     <dbl>  <int> <dbl>
#> 1    6.69      2  327.
#> 2    6.27      5  307.
#> 3    6.19      8  288.
#> 4    5.76      9  282.
#> 5    5.70     10  276.
tidy(path)
#> # A tibble: 5 × 4
#>   penalty n_cpts  cost cpts      
#>     <dbl>  <int> <dbl> <list>    
#> 1    6.69      2  327. <int [2]> 
#> 2    6.27      5  307. <int [5]> 
#> 3    6.19      8  288. <int [8]> 
#> 4    5.76      9  282. <int [9]> 
#> 5    5.70     10  276. <int [10]>
autoplot(path)                          # the cost elbow

ggchangepoint feature tour plot

autoplot(path, type = "path")           # changepoints vs penalty

ggchangepoint feature tour plot

autoplot(path, type = "segmentations")  # the candidate models themselves

ggchangepoint feature tour plot

The visualisation layer

autoplot() renders any ggcpt. Options: show_segments (fitted segment means), show_fit (the engine’s own fitted signal, where provided — SMUCE, DeCAFS, CPOP, segmented, bcp, BEAST), show_ci (changepoint-location confidence intervals, where provided — SMUCE/HSMUCE, strucchange, segmented), show_points/show_line, an index for a date axis, and the cptline_* styling arguments (cptline_color, cptline_alpha, cptline_type, cptline_linewidth). Asking for an overlay the result cannot supply warns rather than failing silently.

autoplot(res, show_segments = TRUE, cptline_color = "firebrick",
         cptline_type = "dashed", cptline_linewidth = 0.8)

ggchangepoint feature tour plot

autoplot(res_smuce, show_ci = TRUE, show_fit = TRUE)

Multivariate results facet automatically:

autoplot(res_hd)

The composable layers work inside any ggplot pipeline: geom_changepoint() draws vertical rules, geom_cpt_segment() draws segment levels, geom_cpt_ci() draws horizontal interval whiskers, and stat_changepoint() runs detection inside the plot. theme_ggcpt() is a publication theme and annotate_segments() shades alternating segments.

cp_tbl <- tidy(res)
df <- data.frame(index = seq_along(x), value = x)

ggplot(df, aes(index, value)) +
  annotate_segments(cp = cp_tbl$cp, n = length(x)) +
  geom_line() +
  geom_changepoint(data = cp_tbl, aes(xintercept = cp), color = "red") +
  geom_cpt_segment(
    data = res$segments,
    aes(x = start, xend = end, y = param_estimate, yend = param_estimate),
    inherit.aes = FALSE, color = "darkred", linewidth = 1
  ) +
  theme_ggcpt()

ggchangepoint feature tour plot

ggplot(df, aes(index, value)) +
  geom_line() +
  stat_changepoint(method = "pelt", color = "blue")

ggchangepoint feature tour plot

ci_tbl <- tidy(res_smuce)
ci_tbl$y_pos <- min(x) - 1
ggplot(df, aes(index, value)) +
  geom_line(color = "grey60") +
  geom_cpt_ci(
    data = ci_tbl,
    aes(y = y_pos, xmin = ci_lower, xmax = ci_upper),
    width = 0.6, color = "blue", inherit.aes = FALSE
  ) +
  geom_changepoint(data = ci_tbl, aes(xintercept = cp), color = "blue")

ggcptplot() and ggecpplot() are the original one-call plots for the two classical engines:

ggcptplot(x, change_in = "mean", cp_method = "PELT")

ggchangepoint feature tour plot

ggecpplot(x, algorithm = "divisive", seed = 1)

ggchangepoint feature tour plot

The Bayesian engines get the field’s signature displays: ggcpt_posterior() shows the posterior mean over the series and the per-location changepoint probability (for bcp and BEAST results); ggcpt_runlength() shows the BOCPD run-length posterior as a heatmap.

ggcpt_posterior(res_bcp)
ggcpt_runlength(res_bocpd)

Finally, ggcpt_interactive() turns any result (or any ggplot built from one) into a plotly widget with values on hover. The widget itself is not embedded here, only its class:

class(ggcpt_interactive(res))   # requires plotly
#> [1] "plotly"     "htmlwidget"

Comparing methods

ggcpt_compare() runs several detectors on the same series and renders them faceted (default) or overlaid, honouring future::plan() for parallel execution; ggcpt_compare_table() returns the tidy union of the same runs. A method that finds nothing keeps its panel and contributes an NA row — “no changepoints” is a result, not a missing one.

ggcpt_compare(x, methods = c("pelt", "binseg", "amoc"))

ggchangepoint feature tour plot

ggcpt_compare(x, methods = c("pelt", "binseg"), layout = "overlay")

ggchangepoint feature tour plot

ggcpt_compare_table(x, methods = c("pelt", "binseg", "amoc"))
#> # A tibble: 3 × 3
#>   method    cp cp_value
#>   <chr>  <int>    <dbl>
#> 1 pelt     100    0.369
#> 2 binseg   100    0.369
#> 3 amoc     100    0.369

Batch detection and stability

cpt_batch() runs one detector over many series (matrix, data frame, or list of vectors), also under future::plan(), and returns a tidy ggcpt_batch tibble with list-columns for the per-series changepoints and the ggcpt objects themselves:

XB <- cbind(shifted = x, pure_noise = rnorm(200))
batch <- cpt_batch(XB, method = "pelt")
batch
#> ggcpt_batch (2 series, method: pelt)
#> 
#> # A tibble: 2 × 2
#>   series     n_changepoints
#>   <chr>               <int>
#> 1 shifted                 1
#> 2 pure_noise              0
tidy(batch)
#> # A tibble: 1 × 3
#>   series     cp cp_value
#>   <chr>   <int>    <dbl>
#> 1 shifted   100    0.369
autoplot(batch)

ggchangepoint feature tour plot

cpt_stability() quantifies how fragile a segmentation is: it resamples residuals within the fitted segments, re-runs the detector, and reports the re-detection frequency at every location — a model-agnostic confidence signal for engines with no native intervals:

st <- cpt_stability(x, method = "pelt", B = 30, seed = 1)
st
#> ggcpt_stability (30 bootstrap replicates, method: pelt)
#> 
#> Original changepoints and their re-detection frequency:
#> # A tibble: 1 × 2
#>      cp stability
#>   <int>     <dbl>
#> 1   100         1
autoplot(st)

ggchangepoint feature tour plot

Evaluation against ground truth

cpt_metrics() scores predictions against a known truth: precision, recall and F1 under one-to-one matching, the covering metric and adjusted Rand index in the conventions of van den Burg and Williams (2020), Hausdorff distance, annotation error, and matched MAE/RMSE. cpt_metrics_annotated() averages over multiple annotators, and ggcpt_eval() draws the agreement (true positives, false positives, and misses):

truth <- 100
pred <- tidy(res)$cp
cpt_metrics(pred, truth, n = length(x), margin = 5)
#> # A tibble: 1 × 12
#>       n n_pred n_truth precision recall    f1 covering hausdorff rand_index
#>   <int>  <int>   <int>     <dbl>  <dbl> <dbl>    <dbl>     <dbl>      <dbl>
#> 1   200      1       1         1      1     1        1         0          1
#> # ℹ 3 more variables: annotation_error <int>, mae_matched <dbl>,
#> #   rmse_matched <dbl>
cpt_metrics_annotated(pred, list(100, 101, 99), n = length(x))
#> # A tibble: 1 × 7
#>       n n_annotators n_pred precision recall    f1 covering
#>   <int>        <int>  <int>     <dbl>  <dbl> <dbl>    <dbl>
#> 1   200            3      1         1      1     1    0.993
ggcpt_eval(pred, truth, x, margin = 5)

ggchangepoint feature tour plot

Simulation and canonical signals

cpt_simulate() (alias rcpt()) generates series with known changepoints in mean, variance, both, or slope, under Gaussian, Student-t, AR(1), or random-walk noise; the truth travels with the data in the true_changepoints and true_segments attributes. Five canonical test signals from the literature ship ready-made: signal_blocks() (the Donoho–Johnstone blocks signal (Donoho and Johnstone 1994)), signal_fms(), signal_mix(), signal_teeth(), and signal_stairs().

sim <- cpt_simulate(300, changepoints = c(100, 200), change_in = "mean",
                    params = c(0, 5, 1), seed = 1)
attr(sim, "true_changepoints")
#> [1] 100 200
sim2 <- rcpt(300, changepoints = 150, params = c(0, 3), seed = 2)  # the alias
attr(sim2, "true_changepoints")
#> [1] 150

signals <- list(blocks = signal_blocks(1024, seed = 1),
                fms    = signal_fms(500, seed = 1),
                mix    = signal_mix(500, seed = 1),
                teeth  = signal_teeth(400, seed = 1),
                stairs = signal_stairs(500, seed = 1))
vapply(signals, function(s) length(attr(s, "true_changepoints")), integer(1))
#> blocks    fms    mix  teeth stairs 
#>     11      7      5      3      9
blocks <- signals$blocks
ggplot(blocks, aes(index, value)) +
  geom_line(color = "grey50") +
  geom_vline(xintercept = attr(blocks, "true_changepoints"),
             color = "blue", linewidth = 0.3) +
  labs(title = "The blocks test signal with its true changepoints")

ggchangepoint feature tour plot

Citing the methodology

cpt_cite() returns the verified reference(s) behind a result or a method name, so a write-up can cite the right paper without leaving R; called with no argument it returns the whole method-to-reference table.

cpt_cite("pelt")
#> [pelt] Killick, R., Fearnhead, P. and Eckley, I. A. (2012). Optimal detection of changepoints with a linear computational cost. Journal of the American Statistical Association, 107(500), 1590-1598.
cpt_cite(res)
#> [pelt] Killick, R., Fearnhead, P. and Eckley, I. A. (2012). Optimal detection of changepoints with a linear computational cost. Journal of the American Statistical Association, 107(500), 1590-1598.

Closing note

This tour visited every exported function in the package. For the framework’s design, the mathematics of the wrapped methods, and worked analyses, see vignette("introduction", package = "ggchangepoint"); for method comparison and accuracy evaluation in depth, see vignette("comparison", package = "ggchangepoint").

References

Adams, Ryan Prescott, and David JC MacKay. 2007. “Bayesian Online Changepoint Detection.” arXiv Preprint arXiv:0710.3742.
Anastasiou, Andreas, and Piotr Fryzlewicz. 2022. “Detecting Multiple Generalized Change-Points by Isolating Single Ones.” Metrika 85: 141–74. https://doi.org/10.1007/s00184-021-00821-6.
Arlot, Sylvain, Alain Celisse, and Zaid Harchaoui. 2019. “A Kernel Multiple Change-Point Algorithm via Model Selection.” Journal of Machine Learning Research 20 (162): 1–56.
Bai, Jushan, and Pierre Perron. 1998. “Estimating and Testing Linear Models with Multiple Structural Changes.” Econometrica 66 (1): 47–78.
———. 2003. “Computation and Analysis of Multiple Structural Change Models.” Journal of Applied Econometrics 18 (1): 1–22.
Baranowski, Rafał, Yining Chen, and Piotr Fryzlewicz. 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–72. https://doi.org/10.1111/rssb.12322.
Barry, Daniel, and John A Hartigan. 1993. “A Bayesian Analysis for Change Point Problems.” Journal of the American Statistical Association 88 (421): 309–19.
Beaulieu, Claudie, and Rebecca Killick. 2018. “Distinguishing Trends and Shifts from Memory in Climate Data.” Journal of Climate 31 (23): 9519–43.
Cabrieto, Jedelyn, Janne Adolf, Francis Tuerlinckx, Peter Kuppens, and Eva Ceulemans. 2018. “Detecting Long-Lived Autodependency Changes in a Multivariate System via Change Point Detection and Regime Switching Models.” Scientific Reports 8: 15637.
Chen, Yudong, Tengyao Wang, and Richard J Samworth. 2022. “High-Dimensional, Multiscale Online Changepoint Detection.” Journal of the Royal Statistical Society: Series B 84 (1): 234–66.
Donoho, David L, and John M Johnstone. 1994. “Ideal Spatial Adaptation by Wavelet Shrinkage.” Biometrika 81 (3): 425–55. https://doi.org/10.1093/biomet/81.3.425.
Eichinger, Birte, and Claudia Kirch. 2018. “A MOSUM Procedure for the Estimation of Multiple Random Change Points.” Bernoulli 24 (1): 526–64. https://doi.org/10.3150/16-BEJ887.
Erdman, Chandra, and John W Emerson. 2007. “Bcp: An r Package for Performing a Bayesian Analysis of Change Point Problems.” Journal of Statistical Software 23 (3): 1–13.
Fearnhead, Paul, and Daniel Grose. 2024. “Cpop: Detecting Changes in Piecewise-Linear Signals.” Journal of Statistical Software 109 (7): 1–30.
Fearnhead, Paul, Robert Maidstone, and Adam Letchford. 2019. “Detecting Changes in Slope with an L0 Penalty.” Journal of Computational and Graphical Statistics 28 (2): 265–75.
Frick, Klaus, Axel Munk, and Hannes Sieling. 2014. “Multiscale Change Point Inference.” Journal of the Royal Statistical Society: Series B 76 (3): 495–580.
Fryzlewicz, Piotr. 2014. “Wild Binary Segmentation for Multiple Change-Point Detection.” The Annals of Statistics 42 (6): 2243–81. https://doi.org/10.1214/14-AOS1245.
———. 2018. “Tail-Greedy Bottom-up Data Decompositions and Fast Multiple Change-Point Detection.” The Annals of Statistics 46 (6B): 3390–3421.
———. 2020. “Detecting Multiple Change-Point Features via Narrowest-over-Threshold.” Journal of the Royal Statistical Society Series B 82 (5): 1377–1418.
Grundy, Thomas, Rebecca Killick, and Gueorgui Mihaylov. 2020. “High-Dimensional Changepoint Detection via a Geometrically Inspired Mapping.” Statistics and Computing 30: 1155–66.
Haynes, Kaylea, Paul Fearnhead, and Idris A Eckley. 2017. “A Computationally Efficient Nonparametric Approach for Changepoint Detection.” Statistics and Computing 27 (5): 1313–29. https://doi.org/10.1007/s11222-016-9687-5.
James, Nicholas A, and David S Matteson. 2014. “Ecp: An R Package for Nonparametric Multiple Change Point Analysis of Multivariate Data.” Journal of Statistical Software 62 (7): 1–25. https://doi.org/10.18637/jss.v062.i07.
Killick, Rebecca, and Idris Eckley. 2014. “Changepoint: An R Package for Changepoint Analysis.” Journal of Statistical Software 58 (3): 1–19. https://doi.org/10.18637/jss.v058.i03.
Killick, Rebecca, Paul Fearnhead, and Idris A Eckley. 2012. “Optimal Detection of Changepoints with a Linear Computational Cost.” Journal of the American Statistical Association 107 (500): 1590–98. https://doi.org/10.1080/01621459.2012.737745.
Li, Xingchi, and Xianyang Zhang. 2024. “Fastcpd: Fast Change Point Detection in r.” arXiv Preprint arXiv:2404.05933.
Maidstone, Robert, Toby Hocking, Guillem Rigaill, and Paul Fearnhead. 2017. “On Optimal Multiple Changepoint Algorithms for Large Data.” Statistics and Computing 27 (2): 519–33. https://doi.org/10.1007/s11222-016-9636-3.
Matteson, David S, and Nicholas A James. 2014. “A Nonparametric Approach for Multiple Change Point Analysis of Multivariate Data.” Journal of the American Statistical Association 109 (505): 334–45.
McGonigle, Euan T, and Haeran Cho. 2025. “Nonparametric Data Segmentation in Multivariate Time Series via Joint Characteristic Functions.” Biometrika 112 (2): asaf024.
Muggeo, Vito MR. 2003. “Estimating Regression Models with Unknown Break-Points.” Statistics in Medicine 22 (19): 3055–71.
———. 2008. “Segmented: An r Package to Fit Regression Models with Broken-Line Relationships.” R News 8 (1): 20–25.
Pein, Florian, Hannes Sieling, and Axel Munk. 2017. “Heterogeneous Change Point Inference.” Journal of the Royal Statistical Society: Series B 79 (4): 1207–27.
Robinson, David. 2017. “Broom: An R Package for Converting Statistical Analysis Objects into Tidy Data Frames.” Journal of Open Source Software 2 (19): 401. https://doi.org/10.21105/joss.00401.
Romano, Gaetano, Guillem Rigaill, Vincent Runge, and Paul Fearnhead. 2022. “Detecting Abrupt Changes in the Presence of Local Fluctuations and Autocorrelated Noise.” Journal of the American Statistical Association 117 (540): 2147–62.
Ross, Gordon J. 2015. “Parametric and Nonparametric Sequential Change Detection in r: The Cpm Package.” Journal of Statistical Software 66 (3): 1–20.
van den Burg, Gerrit J J, and Christopher K I Williams. 2020. “An Evaluation of Change Point Detection Algorithms.” arXiv Preprint arXiv:2003.06222. https://doi.org/10.48550/arXiv.2003.06222.
Wang, Tengyao, and Richard J Samworth. 2018. “High Dimensional Change Point Estimation via Sparse Projection.” Journal of the Royal Statistical Society: Series B 80 (1): 57–83.
Wickham, Hadley. 2016. Ggplot2: Elegant Graphics for Data Analysis. Springer. https://doi.org/10.1007/978-3-319-24277-4.
Zeileis, Achim, Friedrich Leisch, Kurt Hornik, and Christian Kleiber. 2002. “Strucchange: An r Package for Testing for Structural Change in Linear Regression Models.” Journal of Statistical Software 7 (2): 1–38.
Zhao, Kaiguang, Michael A Wulder, Tongxi Hu, et al. 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.
Zhao, Zifeng, Feiyu Jiang, and Xiaofeng Shao. 2022. “Segmenting Time Series via Self-Normalisation.” Journal of the Royal Statistical Society: Series B 84 (5): 1699–1725.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.