A unified interface for time series analysis and forecasting. All models — parametric (e.g. linear trend), ML/DL (via Darts), and ensembles — share the same TimeSeriesModel interface.
- Statistical testing — stationarity, seasonality, normality, white noise, heteroscedasticity, Granger causality
- Decomposition — imperative workflow with automatic recomposition: trend removal, scaling, arbitrary transforms
- Visualization —
signal.plotaccessor with matplotlib and Plotly backends - Pluggable models —
LinearTrend,MovingAverageTrend,HPFilterTrend,STLTrend,EMDTrend,HighPassFilterTrend,Differencing,DartsModel,AggregatedModel
pip install git+https://github.com/eurobios-mews-labs/pastsSignal (extends DataCube)
├── TimeSeriesModel (ABC) — unified fit / transform / reverse_transform
│ ├── LinearTrend — linear parametric model
│ ├── NonParametricTrend — MovingAverage, HPFilter, STL, EMD, HighPassFilter
│ ├── DartsModel — wraps any Darts ML/DL estimator
│ └── AggregatedModel — RMSE-weighted ensemble
├── Decomposition — records and reverses signal transformations
├── ValidationAccessor (.validation) — train/test splits, optional cross-validation
├── StatAccessor (.stat) — statistical tests per column
├── Metrics — R², MSE, RMSE, MAPE, SMAPE, MAE
└── PlotAccessor (.plot) — matplotlib / Plotly plots
Typical workflow:
signal.stat.test_*()— run statistical testssignal.validation_split()— define train/test boundarysignal.decompose()+signal.decompositions["name"].apply_model()— decompose and fit modelssignal.forecast()— predict through decomposition back to original spacesignal.compute_scores()— evaluate metrics on held-out setsignal.apply_model(AggregatedModel(...))— combine models weighted by RMSE
Full example: examples/readme/model.py
import pandas as pd
from darts.datasets import ETTh1Dataset
from pasts.signal import Signal
# Electricity Transformer Temperature — 7 variables (6 power loads + oil temperature)
# Hourly data from 2016-07 to 2018-06 (~17 400 observations)
series = ETTh1Dataset().load()
df_all = pd.DataFrame(series.values())
df_all.columns = ['HUFL', 'HULL', 'MUFL', 'MULL', 'LUFL', 'LULL', 'OT']
df_all.index = series.time_index
# Resample to daily frequency for manageable computation
df_daily = df_all.resample('D').mean()
# Focus on Oil Temperature (OT), the main target variable
dt = df_daily[['OT']]
signal = Signal(dt, path='examples/readme/ETTh1_univariate')All tests return a pd.DataFrame and are applied per-column on multivariate data.
Results are also stored in signal.tests_stat.
signal.stat.test_stationarity()
signal.stat.test_stationarity(method='kpss')
signal.stat.test_seasonality()signal.plot() # raw signal
signal.plot.acf() # autocorrelation functiontimestamp = '2018-04-01'
signal.validation_split(timestamp=timestamp)
signal.train_data # pd.DataFrame — computed on demand
signal.test_data # pd.DataFrame — computed on demandsignal.validation.split(timestamp) is the accessor form; both are equivalent.
Named decompositions allow trend removal while keeping everything linked to the parent signal. The split defined on the parent is automatically shared with each decomposition.
from pasts.components import MovingAverageTrend
signal.decompose("MA_Trend")
signal.decompositions["MA_Trend"] -= MovingAverageTrend(30)Each operation is recorded symbolically; compose() walks the stack in reverse to reconstruct
the original signal from a predicted residual.
Available trend components:
| Component | Description |
|---|---|
LinearTrend |
Linear parametric model |
MovingAverageTrend |
Moving average filter |
HPFilterTrend |
Hodrick-Prescott filter |
STLTrend |
STL decomposition |
EMDTrend |
Empirical Mode Decomposition |
HighPassFilterTrend |
High-pass frequency filter |
Differencing |
Transform-based detrending via DataCube.apply() |
Models are applied directly on a named decomposition.
save_model=True persists the fitted estimator and its predictions to disk (joblib, under signal.path).
from darts.models import XGBModel, RandomForestModel
signal.decompositions["MA_Trend"].apply_model(XGBModel(lags=250), save_model=True)
signal.decompositions["MA_Trend"].apply_model(RandomForestModel(lags=250), save_model=True)forecast() composes predictions back to the original signal space through the decomposition.
signal.models["MA_Trend__XGBModel"] is populated with the composed predictions afterwards.
signal.forecast("MA_Trend__XGBModel", 100, save_model=True)
signal.forecast("MA_Trend__RandomForestModel", 100, save_model=True)signal.compute_scores()Available metrics: r2, mse, rmse, mape, smape, mae.
signal.plot.predictions() # predictions vs actualAggregatedModel combines models weighted by their RMSE on test data.
from pasts.components.aggregated_model import AggregatedModel
signal.apply_model(AggregatedModel(
{'MA_Trend__XGBModel': signal.models['MA_Trend__XGBModel']['model'],
'MA_Trend__RandomForestModel': signal.models['MA_Trend__RandomForestModel']['model']},
), save_model=True)
signal.compute_scores(axis=1)
signal.compute_conf_intervals()
signal.forecast("AggregatedModel", 100, save_model=True)signal.plot.forecast() # all models
signal.plot.forecast(aggregated_only=True) # aggregated model onlyThe same workflow applies to multivariate data. test_causality() is available for multivariate signals.
df_m = df_daily[['HUFL', 'MUFL', 'LUFL', 'OT']]
signal_m = Signal(df_m, path='examples/readme/ETTh1_multivariate')
signal_m.stat.test_causality()
timestamp = '2018-04-01'
signal_m.validation_split(timestamp=timestamp)
signal_m.decompose("MA_Trend")
signal_m.decompositions["MA_Trend"] -= MovingAverageTrend(30)
lags = [-325]
signal_m.decompositions["MA_Trend"].apply_model(XGBModel(lags=lags), save_model=True)
signal_m.decompositions["MA_Trend"].apply_model(RandomForestModel(lags=lags), save_model=True)
signal_m.forecast("MA_Trend__XGBModel", 50, save_model=True)
signal_m.forecast("MA_Trend__RandomForestModel", 50, save_model=True)
signal_m.compute_scores(axis=1)
signal_m.apply_model(AggregatedModel(
{'MA_Trend__XGBModel': signal_m.models['MA_Trend__XGBModel']['model'],
'MA_Trend__RandomForestModel': signal_m.models['MA_Trend__RandomForestModel']['model']},
), save_model=True)
signal_m.compute_scores()
signal_m.forecast("AggregatedModel", 50, save_model=True)pip install sphinx sphinx_rtd_theme
cd doc && make htmlThen open doc/_build/html/index.html.







