
Was the change abrupt? A step against a ramp, at every changepoint
Source:R/abruptness.R
cpt_abruptness.RdFor each changepoint of a change in mean, fits the window around it (between the neighbouring changepoints) twice: as a step, which is what every detector assumes, and as a linear ramp from the old level to the new one, with its centre and width estimated. When the ramp fits clearly better, the change took time, and the reported location is the middle of a transition rather than a moment.
Arguments
- fit
A
ggcptobject with a change in mean (or mean and variance).- level
Level of the interval for the transition width, and
1 - levelthe threshold at which the step is rejected. Defaults to0.95.- max_width
Widest ramp considered, in observations. Defaults to half the window.
- x
A
ggcpt_abruptnessobject.- ...
Ignored.
- object
A
ggcpt_abruptnessobject.
Value
A ggcpt_abruptness tibble with one row per changepoint:
cp, window_start, window_end, width (the
best ramp width, in observations), width_lower and
width_upper (its interval), centre (the ramp's centre),
statistic (the likelihood-ratio statistic against the step),
p_value and verdict ("abrupt" when the step is
not rejected, "gradual" when it is). autoplot() draws
each window with the step and the ramp; print() and
tidy() work as usual.
How it decides
For a ramp of width \(w\) centred at \(c\), the level is \(a\)
before \(c - w/2\), \(b\) after \(c + w/2\), and linear between,
so for fixed \((c, w)\) the fit is ordinary least squares in
\((a, b)\). The residual sum of squares is profiled over the centre
for each width on a grid (every width up to 8, then geometric), and the
step is the width-0 member of the family. The statistic
\(m \log(RSS_{step} / RSS_{ramp})\) over the window's \(m\)
observations is compared with a chi-squared distribution on one degree
of freedom. The step sits on the boundary of the family, which makes
that reference conservative, and the search over widths and centres,
which makes it liberal; measured on true steps (jumps of 1 to 8 noise
standard deviations, \(n\) of 300 and 1,000, Gaussian and \(t_3\)
noise, 400 replicates each, detected with pelt), the step was
rejected in 1.0 to 5.2 per cent of fits at level = 0.95. A ramp
of 2 standard deviations over 30 observations was called gradual in 53
per cent of fits at \(n = 300\), over 60 observations in 70 per cent.
The width interval collects every width whose profile statistic is
within the chi-squared quantile of the best.
A ramp also fits a step plus a few outliers near it, and a window that
holds a second, undetected change; read "gradual" as "a step is
not an adequate description", and look at autoplot().
See also
cpt_simulate() with transition, to measure
how a detector places a gradual change; cpt_gof().
Other inference:
cpt_assumptions(),
cpt_attribute(),
cpt_attribute_event(),
cpt_confint_coverage(),
cpt_effect(),
cpt_gof(),
cpt_k_weights(),
cpt_null_power(),
cpt_robustness(),
cpt_screen(),
cpt_test_at(),
cpt_test_null()
Examples
set.seed(2026)
ramp <- c(rep(0, 100), seq(0, 4, length.out = 30), rep(4, 100))
fit <- cpt_detect(ramp + rnorm(230, 0, 0.5), method = "pelt")
cpt_abruptness(fit)
#> ggcpt_abruptness (a step against a ramp at each changepoint)
#> Changepoint 116: gradual, transition width 24 (24 to 31)
#>
#> # A tibble: 1 × 10
#> cp window_start window_end width width_lower width_upper centre statistic
#> <int> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 116 1 230 24 24 31 115 82.2
#> # ℹ 2 more variables: p_value <dbl>, verdict <chr>
step <- cpt_detect(c(rnorm(100), rnorm(100, 4)), method = "pelt")
cpt_abruptness(step)
#> ggcpt_abruptness (a step against a ramp at each changepoint)
#> Changepoint 100: gradual, transition width 3 (1 to 16)
#>
#> # A tibble: 1 × 10
#> cp window_start window_end width width_lower width_upper centre statistic
#> <int> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 100 1 200 3 1 16 100 4.43
#> # ℹ 2 more variables: p_value <dbl>, verdict <chr>