Skip to contents

Computes data-driven window lengths (in **seconds**) for seasonal (`frequency`) and trend (`trend`) components used by anomalize::time_decompose (works for both method = "stl" and method = "twitter"). The primary estimator selects the earliest statistically significant **local maximum** in the autocorrelation function (ACF). If no such peak exists, a fallback uses the dominant peak of the periodogram (excluding near-DC). The resulting base period is then scaled and clamped to avoid pathological window sizes.

Usage

decomp_freq_trend(
  ts,
  fac.f = 1,
  fac.t = 1.5,
  max_period_frac = 0.2,
  lag.max = NULL,
  use_fft_fallback = TRUE
)

Arguments

ts

A numeric or ts time series. If ts, its frequency(ts) is used upstream when computing the ACF; here we only consume the ACF output assuming lags are already in seconds.

fac.f

Numeric scalar. Multiplier for the seasonal window (default 1.0). For the Twitter method, 1.0 aligns with the base period; increase to widen the seasonal window.

fac.t

Numeric scalar. Multiplier for the trend window (default 1.5). Typical Twitter heuristic is ~1.5–2.0.

max_period_frac

Numeric in (0,1). Upper bound on the candidate period as a fraction of the series duration (default 0.2). Prevents overly long periods relative to batch length.

lag.max

Integer. Maximum lag forwarded to ACF() (default: min(4096, length(ts)-1)).

use_fft_fallback

Logical. If TRUE (default), use stats::spec.pgram fallback when no significant ACF peak is found.

Value

A list with two numeric scalars (in **seconds**):

  • freq — seasonal window length for frequency=

  • trend — trend window length for trend=

These strings are typically passed as paste(value, "seconds") to anomalize::time_decompose().

Details

- Assumes the input ACF() returns lag in **seconds** (as in your current implementation). The effective sampling interval \(\Delta t\) is inferred as median(diff(lag)). - **Primary rule**: pick the first lag \(\tau > 0\) such that \(\mathrm{ACF}(\tau)\) is a local maximum and exceeds the white-noise 95% CI. - **Fallback**: choose \(\tau = (1/f_\mathrm{dom}) \Delta t\) from the dominant periodogram frequency (excluding a small region near DC). - Windows are constructed as $$\mathrm{frequency} = \max(2\Delta t, \min(f_\mathrm{fac}\,\tau, \tau_\max))$$ $$\mathrm{trend} = \max(1.1\,\mathrm{frequency}, \min(t_\mathrm{fac}\,\tau, \tau_\max))$$ where \(\tau_\max = \min(\max(\mathrm{lag}),\, \mathrm{max\_period\_frac}\cdot N\Delta t)\).

See also

acf, spec.pgram, time_decompose

Examples

if (FALSE) { # \dontrun{
ft <- decomp_freq_trend(ts, fac.f = 1.0, fac.t = 1.5)
anomalize::time_decompose(df, observed,
    method = "twitter",
    frequency = paste(ft$freq, "seconds"),
    trend = paste(ft$trend, "seconds")
)
} # }