X-11 style seasonal adjustment for any cycle length (daily, weekly, ...): multiplicative, additive, and log-additive decomposition
Project description
seasadj
X-11 style seasonal adjustment, generalized to an arbitrary cycle length.
period=7 for the day-of-week cycle of daily data, period=24 for the
daily cycle of hourly data, or any other cycle length your data has —
X-13ARIMA-SEATS only handles monthly and quarterly data, and this package
covers the rest.
Why this exists
X-13ARIMA-SEATS is the standard tool for seasonal adjustment, but its X-11 core is hard-wired for monthly (period 12) or quarterly (period 4) data. More and more real series — daily data with a weekly cycle, hourly data with a daily cycle, etc. — don't fit that mold.
This package takes the X-11 procedure apart: outlier, holiday and level-shift adjustment and forecast extension are left to X-13ARIMA-SEATS's RegARIMA pre-adjustment, which works for any cycle length and has a proven track record. The cycle-length-bound X-11 core — moving averages, automatic seasonal filter selection, extreme-value replacement — is reimplemented here, generalized to any cycle length.
Features
- Multiplicative, additive and log-additive decomposition modes
- Log-additive mode includes the Thomson & Ozaki (2002) trend bias correction
- Outlier handling via SI ratios (X-11 extreme value replacement)
- Automatic seasonal filter selection (3x3/3x5/3x9) via the moving seasonality ratio (MSR)
- Automatic Henderson moving average term selection
- Zero dependencies (standard library only)
Install
pip install seasadj
Quick start
import math
from seasadj import decompose
# a synthetic series with a 7-day seasonal cycle
data = [100 + 0.05 * i + 20 * math.sin(2 * math.pi * i / 7) for i in range(400)]
result = decompose(data, period=7)
print(result.trend[:5]) # trend-cycle component
print(result.seasonal[:5]) # seasonal component
print(result.adjusted[:5]) # seasonally adjusted series
print(result.irregular[:5]) # irregular component
decompose() returns a Decomposition with trend, seasonal, adjusted
and irregular series (all plain lists), plus the original observed
series and diagnostics. For multiplicative/log models,
prior_adjusted ≈ trend * seasonal * irregular; for the additive model,
prior_adjusted ≈ trend + seasonal + irregular.
Preparing inputs with X-13ARIMA-SEATS
decompose() expects data that has already been adjusted for holidays,
outliers and level shifts (or you can pass those effects directly — see the
API reference below) and, optionally, a forecast extension. The usual way to
get these is a RegARIMA run in X-13ARIMA-SEATS:
- Multiplicative or log model: run X-13 without a
transform(or withtransform function=nonefor the regressors), and use its multiplicative effect estimates (values near 1.0) asholiday_effect/ao_effect/ls_effect. - Additive model: run X-13 with
transform function=none, and use its additive effect estimates (values near 0.0, the "amount to subtract") as the same arguments.
Mixing the two — e.g. passing multiplicative-style effect factors while
model="additive" — will silently produce a wrong adjustment, since the
additive model treats the effect arguments as amounts to subtract, not
factors to divide by.
File mode (Fortran-compatible CLI)
For compatibility with the original Fortran program, seasadj also has a
file-based mode that reads a working directory laid out as
in_data/ + para/ and writes out_data/:
seasadj <workdir>
# or
python -m seasadj <workdir>
See docs/porting-notes.ja.md for the file formats and module-to-Fortran-source mapping (developer-facing, Japanese).
API reference
decompose(data, period, **kwargs) -> Decomposition
| Argument | Default | Description |
|---|---|---|
data |
required | Observed values (list/tuple/np.ndarray/pd.Series of numbers) |
period |
required | Seasonal cycle length (2 or larger), e.g. 7 for a day-of-week cycle |
first_position |
1 |
Cycle position of data[0] (1..period) |
model |
"multiplicative" |
"multiplicative", "additive" or "log" |
forecast |
None |
Forecast-extension values (e.g. from X-13ARIMA-SEATS) |
holiday_effect |
None |
Holiday prior-adjustment factor per period |
holiday_regressor |
None |
Holiday regression variable; required if holiday_effect and forecast are both given |
holiday_coef |
0.0 |
Holiday regression coefficient |
ao_effect |
None |
Additive-outlier prior-adjustment factor |
ls_effect |
None |
Level-shift prior-adjustment factor |
seasonal_ma |
3 |
Initial seasonal moving average term: 3, 5 or 9 (3x3/3x5/3x9) |
replace_extreme |
True |
Outlier replacement (X-11 extreme value replacement) |
sigma |
(1.5, 2.5) |
(lower, upper) sigma limits for outlier replacement |
ft_o |
1 |
Running position of the first observation (rarely changed) |
verbose |
False |
If True, print progress lines; otherwise they land in diagnostics["log"] |
Raises SeasadjError on invalid input. Validation reports the first
failure it finds, checking data length before checking that values are
positive (relevant for the multiplicative and log models).
Decomposition
All series are plain 0-based lists. n_total = n_observed + n_forecast;
index n_observed onward is the forecast-extension period.
| Field | Length | Content |
|---|---|---|
observed |
n_observed | The input data |
prior_adjusted |
n_total | Data after holiday/outlier/level-shift adjustment (log model: back-transformed to the original scale) |
trend |
n_total | Trend-cycle component |
seasonal |
n_total | Seasonal component |
irregular |
n_total | Irregular component |
adjusted |
n_total | Seasonally adjusted series |
holiday_effect / ao_effect / ls_effect |
n_total | The effect series actually applied |
n_observed / n_forecast |
int | Observed / forecast-extension length |
period |
int | Echoes the period argument |
model |
str | Echoes the model argument |
diagnostics |
dict | h_terms, sum_ratios, swm_term, msr_ratio, msr_count, si_replaced, bias_sig, log |
internals |
dict | Intermediate series (TC1, SI1, w1, SI1r, S1p, S1, A1, TC2, SI2, w2, SI2r, S2p) and ft_SI1; series-edge padding (0.0 / -999.0 / weight 1.0) follows the same convention as the file-mode output |
Algorithm
The X-11 procedure estimates trend-cycle, seasonal and irregular components in three passes (initial trend → intermediate estimate → final estimate), each refining the previous one's seasonal factor and Henderson-filtered trend. This package generalizes every step — the seasonal moving average, the Henderson filter term selection, the moving seasonality ratio, the extreme-value replacement — from the fixed periods of the original X-11 (12 or 4) to an arbitrary period.
References: Dagum, E. B. (1988), The X-11-ARIMA/88 Seasonal Adjustment Method; the JDemetra+ X-11 theory documentation; Thomson, P. and Ozaki, T. (2002), trend bias correction for log-additive decomposition.
Development / testing
This package is a port of an original Fortran90 implementation (Ver16_00),
verified against 7 frozen golden-test cases (not distributed with this
package — see docs/porting-notes.ja.md) to match
bit-for-bit. The tests distributed with this package
(tests/test_api.py) instead check the decomposition identity and the
equivalence of the API and file-mode code paths on artificial data.
pip install -e . pytest
python -m pytest tests/ -v
Citation
If you use this package in research, please cite:
Arita, Tetsuma (2022). "Assessment of the spread of COVID-19 in seven countries using a seasonal adjustment method." Statistical Journal of the IAOS. https://doi.org/10.3233/SJI-220932
A paper describing the Ver14-16 extensions implemented in this package (extreme SI-ratio replacement, additive/log-additive modes, Thomson & Ozaki trend bias correction) is in preparation; this citation will be updated once it is available.
License / Commercial use
seasadj is licensed under the GNU Affero General Public License v3.0 or
later (AGPL-3.0-or-later) — see LICENSE.
If the AGPL's terms don't work for your use case (e.g. embedding in proprietary software), or if you are interested in research collaboration or customization, inquiries are welcome — please open an issue on GitHub to get in touch.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file seasadj-1.0.0.tar.gz.
File metadata
- Download URL: seasadj-1.0.0.tar.gz
- Upload date:
- Size: 47.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c6d1ec954df696692291b4d31465489289aa302f4aa46bf48db8b3f4ab03576a
|
|
| MD5 |
32ed768eb681dd9675c6ce68494ece7e
|
|
| BLAKE2b-256 |
518f4ef301166ebe600fcf99ee31cc5574f50735e34da20d0ab5fcd85258c1e3
|
File details
Details for the file seasadj-1.0.0-py3-none-any.whl.
File metadata
- Download URL: seasadj-1.0.0-py3-none-any.whl
- Upload date:
- Size: 45.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
88fe3eab059312eb7fdec81efc176f66d4bde1fce2c0922b80c6d76d1f837361
|
|
| MD5 |
9013dd671b32a2ec03a9eb52d9332f5c
|
|
| BLAKE2b-256 |
1ecb8496ec12a802c5ff08480a7a29184f1ea6ccf70b95355ed6ee70749d08cd
|