Skip to contents

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.

Usage

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,
  ...
)

Arguments

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: "covariance" (default), "trace", "eigenjoint" or "eigensingle". This is also by far the biggest lever on run time (see the timing section below), and note that the four answer different questions, so a cheaper one is a different test rather than a faster route to the same answer.

statistic

Test statistic: "Tn" (integrated, the default) or "Mn" (maximum).

critical

How critical values are obtained: "simulation" (default), "resample" or "welch". The first two draw random numbers and there is no seed argument, so call set.seed() first when the answer has to be reproducible.

type

"segmentation" (default, multiple changes) or "single" (one change).

alpha

Significance level. Defaults to 0.05.

...

Additional arguments passed to fChange::fchange().

Value

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.

How long this takes

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:

inputfmeanfcov
\(n = 60\), \(p = 5\)4.5 s316 s
\(n = 120\), \(p = 5\)2.9 s598 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 \(n = 60\), \(p = 6\), M = 50 on one Linux x86-64 machine:

targettimechangepoints found
"covariance" (default)477 snone
"eigenjoint"21.7 snone
"eigensingle"21.7 snone
"trace"2.1 s16, 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 \(n = 120\) 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.

References

Aue A, Rice G, Sönmez O (2020). “Structural break analysis for spectrum and trace of covariance operators.” Environmetrics, 31(1), e2617.

Examples

# \donttest{
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)
#> ggcpt (changepoint detection result)
#>   Method:             fcov
#>   Change in:          covariance
#>   Changepoints found: 1
#>   CP convention:      left
#>   Penalty:            alpha = 0.05
#>   Series length:      60
#> 
#> Changepoints:
#> # A tibble: 1 × 3
#>      cp cp_value p_value
#>   <int>    <dbl>   <dbl>
#> 1    30    0.439       0
# }