Skip to contents

seasight provides tools to see seasonal adjustment more clearly. It wraps the seasonal interface to X-13ARIMA-SEATS with:

  • summary diagnostics,
  • automatic model selection, and
  • reproducible HTML reports.

The main target audience are applied economists and official statisticians who need stable, well-documented seasonal adjustment workflows, e.g. in National Accounts or short-term indicators.

The design follows the recommendations in Eurostat’s ESS Guidelines on Seasonal Adjustment and the Handbook on Seasonal Adjustment.(European Commission)

How this package differs from alternatives

seasight is designed to complement the core seasonal API.

  • Keep using seasonal::seas() when you need direct hand-crafted X-13 calls.
  • Use seasight when you need a standardized and auditable workflow around those calls (candidate grids, diagnostics, ranking, and reporting artifacts).

In other words, seasight focuses on decision support and reproducibility in institutional workflows, while the decomposition engine remains X-13 via seasonal.

Setup

library(seasight)
library(seasonal)

# Example monthly time series from base R
x <- AirPassengers
x

We assume that X-13ARIMA-SEATS is available via the seasonal package (see ?seasonal::seas for installation details).

A first seasonal adjustment with seasonal

In production you typically start from a manually maintained X-13 specification. Here we use the very simple default call:

m_current <- seas(x)
summary(m_current)

m_current is a regular seasonal::seas object. seasight does not replace seasonal – it sits on top and helps you:

  • assess the quality of a given model,
  • explore alternative specifications, and
  • document the decision in a consistent way.

Low-level diagnostics: sa_tests_model()

The basic diagnostic building block is sa_tests_model(). It computes a set of standard tests for a single seas model:

tests_current <- sa_tests_model(m_current)
tests_current

For the 0.1.x pre-submission cycle, the core user-facing outputs are frozen; typical fields include:

  • Residual seasonality (QS on SA) X-11/SEATS QS statistics on the seasonally adjusted series.
  • Seasonality in the original series (QSori) QS statistics on the unadjusted series.
  • M7 X-11 M-statistics for residual seasonality (M7 is the main one used by Eurostat).(European Commission)
  • IDS The “identifiable seasonality” indicator used in Eurostat practice.
  • Residual autocorrelation (Ljung–Box) A basic check that the ARIMA model is absorbing the dynamics.
  • Volatility reduction How much the standard deviation of growth rates falls when moving from raw to seasonally adjusted data.
  • Seasonal amplitude Size of the seasonal component relative to the series level.

These metrics are the raw ingredients for the higher-level decisions discussed below.

Automatic model search: auto_seasonal_analysis()

auto_seasonal_analysis() searches over a grid of candidate X-13 specs and ranks them according to a composite score:

res <- auto_seasonal_analysis(
  y                = x,
  use_fivebest     = TRUE,
  include_easter   = "auto",
  td_usertype      = "td",
  engine           = "auto"   # let seasight choose between SEATS / X-11
)

names(res)

The most important components are:

  • res$best The best seas model (a regular seasonal::seas object).

  • res$table A tibble with one row per candidate, including:

    head(res$table)

    Typical columns include:

    • model_label – a short identifier,
    • ARIMA structure (ARIMA_disp / arima / spec_id),
    • with_td, td_p – trading-day regressor and its p-value,
    • QS_p_x11, QS_p_seats, QS_p – QS on SA,
    • QSori_p_x11, QSori_p_seats, QSori_p – QS on original,
    • LB_p – Ljung–Box p-value,
    • seasonal_amp_pct – seasonal amplitude (% of level),
    • vola_reduction_pct – volatility reduction (%),
    • dist_sa_L1 – L1 distance vs. the current SA (if supplied),
    • rev_mae – mean absolute revision (if history info is available),
    • score – the composite score used for ranking.
  • res$seasonality A nested list with an “existence-of-seasonality” decision for the original series, based on QS, IDS and M7 (see Eurostat guidelines).(European Commission)

Calendar regressors (trading days & moving holidays)

seasight can compare models without regressors against models with user-supplied calendar regressors via td_candidates.

A key design choice: the package does not ship country-specific calendars. Instead you can build generic regressors yourself and pass them in.

# Example: build a Diwali "pulse" regressor (quarterly here, for illustration)
diwali_dates <- as.Date(c(
  "2018-11-07","2019-10-27","2020-11-14","2021-11-04",
  "2022-10-24","2023-11-12","2024-11-01"
))

td <- build_user_xreg(
  y = x,
  holidays = list(diwali = list(dates = diwali_dates, start = -1, end = 1)),
  td_usertype = "holiday"
)

res_td <- auto_seasonal_analysis(x, td_candidates = td, engine = "auto")

For more realistic workflows (multiple TD candidates, baselines, and decision rules), see the SA practice and Advanced vignettes.

Inspecting the winning model

The winning model is in res$best:

best <- res$best
summary(best)

You can use it like any other seas object:

final(best)[1:6]
original(best)[1:6]
resid(best)[1:6]

If you prefer to keep everything explicit, you can access the underlying specification as R code using sa_copyable_call() (also shown in the HTML report, see below):

sa_copyable_call(best, x_expr = "AirPassengers")

Visual “cards”: sa_existence_card() and sa_engine_choice_card()

In interactive HTML outputs (e.g. pkgdown site, Quarto, Shiny) it is often helpful to summarise key decisions in compact “cards”.

seasight exposes two such cards:

# Existence-of-seasonality card
sa_existence_card(res)

# Engine choice card (SEATS vs X-11)
sa_engine_choice_card(res)
  • The existence card explains whether the series should be adjusted, combining QS, M7 and IDS into a single “robust” call.
  • The engine card provides a transparent rationale for choosing SEATS vs X-11 based on their diagnostics and stability.

From analysis to decision: sa_should_switch()

If you provide a current (baseline) model, seasight can suggest whether you should keep it or switch to the new best candidate.

res_with_baseline <- auto_seasonal_analysis(
  y             = x,
  current_model = m_current
)

sa_should_switch(res_with_baseline)

The decision rule takes into account:

  • whether the new model passes basic diagnostics (QS / Ljung–Box),
  • whether the new seasonal pattern is materially different from the current one (L1 distance, correlation of seasonal factors),
  • and whether the new model improves the composite score.

You can always override this decision – the goal is to provide a transparent, reproducible default that is broadly aligned with Eurostat practice (e.g. avoid switching for tiny cosmetic improvements).(European Commission)

A full HTML report in one call: sa_report_html()

For documentation, review meetings or method reports you often want a self-contained HTML document:

tmp_file <- tempfile(fileext = ".html")

sa_report_html(
  y             = x,
  current_model = m_current,
  title         = "AirPassengers – seasight demo",
  outfile       = tmp_file
)

tmp_file
# Browse to this file in your file manager or with browseURL(tmp_file)

The report includes:

  • an executive summary (existence of seasonality, best model, decision),
  • narrative cards explaining why the model was chosen,
  • comparison plots vs. the current model (levels and growth),
  • diagnostics (QS, M7, IDS, Ljung–Box, seasonal amplitude, volatility reduction),
  • outlier listings for current and new model,
  • copy-pasteable seas() calls for both specifications, and
  • a “Top candidates” table with the highest-ranked alternatives.

Where to go next

For a deeper dive into:

  • using baselines (current production models),
  • passing custom trading-day candidates, and
  • understanding the built-in decision rules,

see the companion vignette:

“Advanced usage: baselines, TD candidates & decision rules”

which uses the same AirPassengers series but goes further into methodological details.