LGTD: Local–Global Trend Decomposition
Season-length-free time series decomposition.
LGTD (Local–Global Trend Decomposition) is a principled method for decomposing a univariate time series into trend, seasonal, and residual components without requiring prior specification of seasonal periods. In contrast to classical decomposition techniques—such as STL, X-11, and MSTL—which assume fixed or user-specified seasonal lengths, LGTD automatically identifies and aggregates repeating structures of arbitrary and potentially time-varying scales.
Motivation
Many real-world time series exhibit seasonality that is non-stationary, intermittent, or composed of multiple overlapping cycles. Period-dependent methods are brittle in such settings, as incorrect or misspecified periods can substantially degrade decomposition quality. LGTD is designed to address this limitation by eliminating the need for explicit period selection.
# STL requires an explicit seasonal period
from statsmodels.tsa.seasonal import STL
stl = STL(y, seasonal=24) # ❌ requires prior knowledge of the period
result = stl.fit()
# LGTD does not require period specification
from lgtd import lgtd
model = lgtd()
result = model.fit_transform(y) # ✅ accommodates variable and unknown periods
Installation
pip install lgtd
Quick Start
from lgtd import lgtd
import numpy as np
# Synthetic time series with trend and seasonality
t = np.arange(500)
y = 0.05 * t + 10 * np.sin(2 * np.pi * t / 24) + np.random.normal(0, 1, 500)
# Decomposition
model = lgtd()
result = model.fit_transform(y)
# Decomposed components
print("Detected periods:", result.detected_periods)
print("Trend:", result.trend)
print("Seasonal:", result.seasonal)
print("Residual:", result.residual)
Key Properties
- Season-length-free — No assumption of known or fixed seasonal periods
- Multiple and time-varying periodicities — Supports overlapping and drifting cycles
- Adaptive trend modeling — Automatically selects between linear and LOWESS trends
- Noise robustness — Stable performance under irregular and noisy observations
- Minimal interface — Simple, scikit-learn–style API
Parameters
model = lgtd(
window_size=3, # Local window size for pattern extraction
error_percentile=50, # Threshold for seasonal pattern aggregation
trend_selection='auto', # {'auto', 'linear', 'lowess'}
lowess_frac=0.1, # LOWESS smoothing fraction
threshold_r2=0.9 # R² threshold for trend selection
)
Refer to the Parameter Guide for detailed tuning guidelines.
Visualization
from lgtd.evaluation.visualization import plot_decomposition
result = model.fit_transform(y)
plot_decomposition(result, title="LGTD Decomposition")
Evaluation Metrics
from lgtd.evaluation.metrics import compute_mse, compute_mae
mse = compute_mse(ground_truth, {
'trend': result.trend,
'seasonal': result.seasonal,
'residual': result.residual
})
Reproducibility
This repository contains a complete experimental pipeline for reproducing the results reported in the accompanying paper. LGTD is evaluated against seven baseline decomposition methods on both synthetic and real-world datasets.
python experiments/scripts/run_synthetic_experiments.py
python experiments/scripts/run_realworld_experiments.py
python experiments/scripts/generate_tables.py
python experiments/scripts/generate_figures.py
See the Experiments Guide for full details.
Documentation
- API Reference — Complete API specification
- Algorithm Details — Mathematical formulation
- Parameter Guide — Hyperparameter analysis
- Experiments — Reproducibility instructions
- Datasets — Dataset descriptions
- Baselines — Comparative methods
Method Overview
LGTD decomposes a time series ( y_t ) as
[ y_t = T_t + S_t + R_t, ]
where ( T_t ) denotes the global trend, ( S_t ) the aggregated seasonal structure, and ( R_t ) the residual component.
High-level procedure:
- Estimate a global trend (linear or LOWESS, selected adaptively)
- Remove the estimated trend
- Identify local linear patterns using sliding windows
- Aggregate consistent patterns into a seasonal component
- Compute residuals
See Algorithm Documentation for formal definitions and analysis.
Citation
@article{lgtd2026arxiv,
title = {LGTD: Local--Global Trend Decomposition for Season-Length-Free Time Series Analysis},
author = {Sophaken, Chotanan and Rattanakornphan, Thanadej and Charoenpoonpanich, Piyanon and Phungtua-eng, Thanapol and Amornbunchornvej, Chainarong},
journal = {arXiv preprint},
year = {2026},
eprint = {2601.04820},
archivePrefix= {arXiv},
primaryClass = {cs.DB}
}
License
Released under the MIT License. See LICENSE for details.
Links
- GitHub: https://github.com/chotanansub/LGTD
- PyPI: https://pypi.org/project/lgtd/
- Issues: https://github.com/chotanansub/LGTD/issues
- Documentation: docs/
Metadata
Release files for lgtd 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lgtd-0.1.0.tar.gz | 16.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lgtd-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 31.6 kB
Release files / lgtd-0.1.0.tar.gz
| Download URL | lgtd-0.1.0.tar.gz |
|---|---|
| Size | 16.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8c420edef685c03e9d15e66bfa20e560d62fad8c33cd19189e29d1612b545fad
|
|
BLAKE2b-256 checksum How to use checksums |
5b0fe392e11d720ec6f67e66047e4d9d70800436cd04fd7ca05fb205dbd9f4a7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.12
|
Release files / lgtd-0.1.0-py3-none-any.whl
| Download URL | lgtd-0.1.0-py3-none-any.whl |
|---|---|
| Size | 15.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1fb61bb5b4a1f2fab568f96dc84e6d6f4c28aabb2ce81712487d68e9658ae218
|
|
BLAKE2b-256 checksum How to use checksums |
88ef273bdcc8aee7295f757b1d864c63d0389fb04d78addbc927f41c2dacabdb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.12
|