
Automatic seasonal analysis (candidate grid + ranking)
Source:R/sa-auto.R
auto_seasonal_analysis.RdRuns a grid of X-13ARIMA-SEATS specifications, computes diagnostics
(QS tests, residual checks, revision metrics, distance to a baseline
model, etc.), and ranks candidates using a composite score. Returns
the best model together with a diagnostic table and seasonality call.
The function may fit several X-13 models; use max_specs for fast
exploratory runs and larger grids for review runs.
Usage
auto_seasonal_analysis(
y,
specs = NULL,
use_fivebest = TRUE,
max_specs = NULL,
seasonal_only = TRUE,
auto_outliers = TRUE,
transform_fun = c("auto", "log", "none"),
td_candidates = NULL,
td_usertype = "td",
include_easter = c("auto", "always", "off"),
easter_len = 15L,
include_history_top_n = 10,
early_period_end = NULL,
current_model = NULL,
current_sa = NULL,
current_seasonal = NULL,
w_qs = 1,
w_stability = 1,
w_aicc = 1,
w_rev = 0.5,
w_dist_sa = 1,
w_dist_seas = 0.5,
w_engine = 1,
engine = c("seats", "x11", "auto"),
outlier_types = c("AO", "LS", "TC"),
outlier_method = "AddOne",
outlier_critical = 4,
outlier_alpha = NULL,
comparison_mode = c("full_search", "incumbent_fixed")
)Arguments
- y
A time series (
ts) or an object that can be converted totsviatsbox::ts_ts().- specs
Optional character vector of ARIMA specifications in the form
"(p d q)(P D Q)". IfNULL, default specs are chosen based on the series frequency.- use_fivebest
Logical. If
TRUE, a small set of data-driven "five best" specs (as inseasonal::seas(x, x11 = "")) is added to the candidate grid.- max_specs
Optional positive integer limiting the number of candidate ARIMA specifications fitted after de-duplication and seasonal filtering.
- seasonal_only
Logical. If
TRUE(default), candidate ARIMA specifications must have a non-zero seasonal order (P + D + Q > 0).- auto_outliers
Logical. If
TRUE, enables automatic outlier detection in the candidate models.- transform_fun
Transformation applied to the input series before seasonal adjustment.
"auto"selects a safe log transform if the series is strictly positive,"log"forces a log transform, and"none"keeps the series in levels.- td_candidates
Optional named list of alternative trading-day regressors, e.g.
list(wd = wd.m, wd1 = wd1.m). Each element should be a time series aligned withy.- td_usertype
Character string passed as
regression.usertypewhenxregis used (default"td").- include_easter
Controls inclusion of Easter regressors:
"auto"(default) asks X-13 to select among its supported Easter windows or reject Easter,"always"fixeseaster[easter_len], and"off"neither includes nor tests Easter. A logical value is also accepted and mapped to"auto"/"off".- easter_len
Integer, length (in days) of the Easter effect imposed by
include_easter = "always". It is ignored in"auto"and"off"modes.- include_history_top_n
Integer, number of top-ranked models for which revision metrics over the history are computed before the final ranking step.
- early_period_end
Reserved for future use. Optional index or date marking the end of an early sample period used for stability checks.
- current_model
Optional incumbent
seasonal::seasobject used as a baseline for distance measures and comparison.- current_sa
Optional baseline seasonally adjusted series. If not supplied, it is extracted from
current_modelwhen possible.- current_seasonal
Optional baseline seasonal component. If not supplied, it is extracted from
current_model(preferring SEATS, falling back to X-11 if needed).- w_qs
Weight of the QS (seasonality) diagnostics in the composite ranking score.
- w_stability
Weight of residual / stability diagnostics (e.g. Ljung-Box) in the composite score.
- w_aicc
Weight of the information criterion (AICc) in the composite score.
- w_rev
Weight of the revision metric (historical revision MAE) in the composite score.
- w_dist_sa
Weight of the distance between seasonally adjusted series (candidate vs baseline) in the composite score.
- w_dist_seas
Weight of the distance between seasonal components (candidate vs baseline) in the composite score.
- w_engine
Weight / penalty term related to the decomposition engine (SEATS vs X-11) in the composite score.
- engine
Engine preference for candidate models. One of
"seats","x11"or"auto"(tries both and lets the ranking decide, with a small penalty for deviations from the preferred engine).- outlier_types
Character vector of outlier types to detect, typically a subset of
c("AO", "LS", "TC").- outlier_method
Character scalar giving the outlier detection method (passed to
seasonal::seas(), e.g."AddOne").- outlier_critical
Numeric critical value for outlier detection (e.g. t- or z-threshold).
- outlier_alpha
Optional numeric significance level for outlier detection. If supplied, it is converted to a two-sided normal cutoff for
outlier_critical.- comparison_mode
Comparison design.
"full_search"(default) lets every candidate select its own regressors and outliers."incumbent_fixed"requirescurrent_model, retains its selected transformation and effective regression variables, and varies only the requested ARIMA specification and decomposition engine. Stored user regressors must be available in the incumbent model.
Value
An object of class "auto_seasonal_analysis" with components
such as best (best seas model), table (diagnostic and ranking
table, including actual Easter inclusion in with_easter and its selected
window in easter_window, SEATS substitution metadata in
SEATS_model_switch and SEATS_operative_model, and peak-to-trough
seasonal amplitude in seasonal_amp_pct. For log models this is the
seasonal-factor range in percentage points; for level models it is the
additive range relative to the median absolute series level), specs_tried,
frequency, transform, baseline, and
seasonality. When current_model is supplied, baseline includes its
diagnostics and an indicator of whether its AICc is comparable with the
selected candidate. comparison_mode and regressor_comparison describe
whether candidate AICc differences hold the incumbent regressors fixed.
Details
Ranking combines residual seasonality on the adjusted series (QS_p),
Ljung-Box residual diagnostics, AICc, revision metrics for the top
candidates, distance from an incumbent model when supplied, and a small
engine-preference penalty.
Examples
# \donttest{
if (requireNamespace("seasonal", quietly = TRUE)) {
res <- auto_seasonal_analysis(
AirPassengers,
max_specs = 3,
include_history_top_n = 2
)
res$seasonality$overall
}
#> Model used in SEATS is different: (1 1 2)(1 0 0)
#> Model used in SEATS is different: (1 1 2)(1 0 0)
#> Model used in SEATS is different: (1 1 1)(1 0 0)
#> seas(
#> x = structure(c(112, 118, 132, 129, 121, 135, 148, 148, 136, 119, 104, 118, 115, 126, 141, 135, 125, 149, 170, 170, 158, 133, 114, 140, 145, 150, 178, 163, 172, 178, 199, 199, 184, 162, 146, 166, 171, 180, 193, 181, 183, 218, 230, 242, 209, 191, 172, 194, 196, 196, 236, 235, 229, 243, 264, 272, 237, 211, 180, 201, 204, 188, 235, 227, 234, 264, 302, 293, 259, 229, 203, 229, 242, 233, 267, 269, 270, 315, 364, 347, 312, 274, 237, 278, 284, 277, 317, 313, 318, 374, 413, 405, 355, 306, 271, 306, 315, 301, 356, 348, 355, 422, 465, 467, 404, 347, 305, 336, 340, 318, 362, 348, 363, 435, 491, 505, 404, 359, 310, 337, 360, 342, 406, 396, 420, 472, 548, 559, 463, 407, 362, 405, 417, 391, 419, 461, 472, 535, 622, 606, 508, 461, 390, 432), tsp = c(1949, 1960.91666666667, 12), class = "ts"),
#> seats.noadmiss = "no",
#> transform.function = "log",
#> arima.model = "(0 1 0)(0 1 1)",
#> seats = "",
#> regression.variables = "easter[8]",
#> regression.aictest = NULL,
#> outlier = NULL
#> )
#> seas(
#> x = structure(c(112, 118, 132, 129, 121, 135, 148, 148, 136, 119, 104, 118, 115, 126, 141, 135, 125, 149, 170, 170, 158, 133, 114, 140, 145, 150, 178, 163, 172, 178, 199, 199, 184, 162, 146, 166, 171, 180, 193, 181, 183, 218, 230, 242, 209, 191, 172, 194, 196, 196, 236, 235, 229, 243, 264, 272, 237, 211, 180, 201, 204, 188, 235, 227, 234, 264, 302, 293, 259, 229, 203, 229, 242, 233, 267, 269, 270, 315, 364, 347, 312, 274, 237, 278, 284, 277, 317, 313, 318, 374, 413, 405, 355, 306, 271, 306, 315, 301, 356, 348, 355, 422, 465, 467, 404, 347, 305, 336, 340, 318, 362, 348, 363, 435, 491, 505, 404, 359, 310, 337, 360, 342, 406, 396, 420, 472, 548, 559, 463, 407, 362, 405, 417, 391, 419, 461, 472, 535, 622, 606, 508, 461, 390, 432), tsp = c(1949, 1960.91666666667, 12), class = "ts"),
#> seats.noadmiss = "no",
#> transform.function = "log",
#> arima.model = "(0 1 0)(0 1 1)",
#> seats = "",
#> regression.variables = "easter[8]",
#> regression.aictest = NULL,
#> outlier = NULL
#> )
#> seas(
#> x = structure(c(112, 118, 132, 129, 121, 135, 148, 148, 136, 119, 104, 118, 115, 126, 141, 135, 125, 149, 170, 170, 158, 133, 114, 140, 145, 150, 178, 163, 172, 178, 199, 199, 184, 162, 146, 166, 171, 180, 193, 181, 183, 218, 230, 242, 209, 191, 172, 194, 196, 196, 236, 235, 229, 243, 264, 272, 237, 211, 180, 201, 204, 188, 235, 227, 234, 264, 302, 293, 259, 229, 203, 229, 242, 233, 267, 269, 270, 315, 364, 347, 312, 274, 237, 278, 284, 277, 317, 313, 318, 374, 413, 405, 355, 306, 271, 306, 315, 301, 356, 348, 355, 422, 465, 467, 404, 347, 305, 336, 340, 318, 362, 348, 363, 435, 491, 505, 404, 359, 310, 337, 360, 342, 406, 396, 420, 472, 548, 559, 463, 407, 362, 405, 417, 391, 419, 461, 472, 535, 622, 606, 508, 461, 390, 432), tsp = c(1949, 1960.91666666667, 12), class = "ts"),
#> seats.noadmiss = "no",
#> transform.function = "log",
#> arima.model = "(1 1 1)(0 1 1)",
#> seats = "",
#> regression.variables = "easter[8]",
#> regression.aictest = NULL,
#> outlier = NULL
#> )
#> seas(
#> x = structure(c(112, 118, 132, 129, 121, 135, 148, 148, 136, 119, 104, 118, 115, 126, 141, 135, 125, 149, 170, 170, 158, 133, 114, 140, 145, 150, 178, 163, 172, 178, 199, 199, 184, 162, 146, 166, 171, 180, 193, 181, 183, 218, 230, 242, 209, 191, 172, 194, 196, 196, 236, 235, 229, 243, 264, 272, 237, 211, 180, 201, 204, 188, 235, 227, 234, 264, 302, 293, 259, 229, 203, 229, 242, 233, 267, 269, 270, 315, 364, 347, 312, 274, 237, 278, 284, 277, 317, 313, 318, 374, 413, 405, 355, 306, 271, 306, 315, 301, 356, 348, 355, 422, 465, 467, 404, 347, 305, 336, 340, 318, 362, 348, 363, 435, 491, 505, 404, 359, 310, 337, 360, 342, 406, 396, 420, 472, 548, 559, 463, 407, 362, 405, 417, 391, 419, 461, 472, 535, 622, 606, 508, 461, 390, 432), tsp = c(1949, 1960.91666666667, 12), class = "ts"),
#> seats.noadmiss = "no",
#> transform.function = "log",
#> arima.model = "(1 1 1)(0 1 1)",
#> seats = "",
#> regression.variables = "easter[8]",
#> regression.aictest = NULL,
#> outlier = NULL
#> )
#> seas(
#> x = structure(c(112, 118, 132, 129, 121, 135, 148, 148, 136, 119, 104, 118, 115, 126, 141, 135, 125, 149, 170, 170, 158, 133, 114, 140, 145, 150, 178, 163, 172, 178, 199, 199, 184, 162, 146, 166, 171, 180, 193, 181, 183, 218, 230, 242, 209, 191, 172, 194, 196, 196, 236, 235, 229, 243, 264, 272, 237, 211, 180, 201, 204, 188, 235, 227, 234, 264, 302, 293, 259, 229, 203, 229, 242, 233, 267, 269, 270, 315, 364, 347, 312, 274, 237, 278, 284, 277, 317, 313, 318, 374, 413, 405, 355, 306, 271, 306, 315, 301, 356, 348, 355, 422, 465, 467, 404, 347, 305, 336, 340, 318, 362, 348, 363, 435, 491, 505, 404, 359, 310, 337, 360, 342, 406, 396, 420, 472, 548, 559, 463, 407, 362, 405, 417, 391, 419, 461, 472, 535, 622, 606, 508, 461, 390, 432), tsp = c(1949, 1960.91666666667, 12), class = "ts"),
#> seats.noadmiss = "no",
#> transform.function = "log",
#> arima.model = "(0 1 1)(0 1 1)",
#> seats = "",
#> regression.variables = "easter[1]",
#> regression.aictest = NULL,
#> outlier = NULL
#> )
#> seas(
#> x = structure(c(112, 118, 132, 129, 121, 135, 148, 148, 136, 119, 104, 118, 115, 126, 141, 135, 125, 149, 170, 170, 158, 133, 114, 140, 145, 150, 178, 163, 172, 178, 199, 199, 184, 162, 146, 166, 171, 180, 193, 181, 183, 218, 230, 242, 209, 191, 172, 194, 196, 196, 236, 235, 229, 243, 264, 272, 237, 211, 180, 201, 204, 188, 235, 227, 234, 264, 302, 293, 259, 229, 203, 229, 242, 233, 267, 269, 270, 315, 364, 347, 312, 274, 237, 278, 284, 277, 317, 313, 318, 374, 413, 405, 355, 306, 271, 306, 315, 301, 356, 348, 355, 422, 465, 467, 404, 347, 305, 336, 340, 318, 362, 348, 363, 435, 491, 505, 404, 359, 310, 337, 360, 342, 406, 396, 420, 472, 548, 559, 463, 407, 362, 405, 417, 391, 419, 461, 472, 535, 622, 606, 508, 461, 390, 432), tsp = c(1949, 1960.91666666667, 12), class = "ts"),
#> seats.noadmiss = "no",
#> transform.function = "log",
#> arima.model = "(0 1 1)(0 1 1)",
#> seats = "",
#> regression.variables = "easter[1]",
#> regression.aictest = NULL,
#> outlier = NULL
#> )
#> # A tibble: 1 × 5
#> call_overall share_ids share_qsori share_m7_strong share_m7_weak
#> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 ADJUST 1 1 1 1
# }