macroforecast.filters#
Purpose#
macroforecast.filters contains direct one-series filter and smoother
callables. These functions transform a single time series and return the
filtered components plus metadata. They do not create forecast targets, do not
build a model-ready feature matrix, and do not decide train/validation/test
windows.
Use macroforecast.feature_engineering when the same filters need to become
panel features such as {column}_hp_cycle, {column}_hamilton_cycle,
{column}_savgol, or {column}_albama.
Public Functions#
Callable |
Input |
Output |
Purpose |
|---|---|---|---|
|
One numeric series. |
|
Two-sided Hodrick-Prescott filter. |
|
One numeric series. |
|
Hamilton regression filter with expanding or full-sample fit policy. |
|
One numeric series. |
|
Centered Savitzky-Golay local polynomial smoother. |
|
One numeric series. |
|
Existing causal rolling multi-resolution approximation. |
|
One numeric series. |
|
Goulet Coulombe-Klieber adaptive learning-based moving average. |
|
Estimator-style smoother settings. |
Object with |
Class wrappers around |
Output Objects#
FilterResult#
macroforecast.filters.FilterResult(
values: pandas.DataFrame,
method: str,
params: dict,
metadata: dict,
source: str | None = None,
)
Field |
Meaning |
|---|---|
|
Filtered component frame indexed like the input series. |
|
Canonical filter name, such as |
|
Resolved parameter values. |
|
Provenance, fit policy, backend, and formula notes. |
|
Source series name when available. |
FilterResult.component(name) returns one component column from values.
AlbaMAResult#
albama() returns AlbaMAResult, not FilterResult, because the learned
observation-weight matrix is central to the method.
Field |
Meaning |
|---|---|
|
Adaptive moving-average series. |
|
Source-date by target-date observation-weight matrix. |
|
|
|
Current backend identifier. |
|
Resolved tree-bagging settings. |
|
Paper reference, R-code reference, and weight-extraction notes. |
Flow#
import macroforecast as mf
hp = mf.filters.hp_filter(inflation, lamb=129600.0)
cycle = hp.component("cycle")
ham = mf.filters.hamilton_filter(inflation, h=24, p=12, fit_policy="expanding")
trend = ham.component("trend")
sg = mf.filters.savitzky_golay(inflation, window_length=13, polyorder=2)
smooth = sg.component("savgol")
albama = mf.filters.albama(inflation, mode="one_sided")
adaptive = albama.smoothed
weights = albama.weights
For panel feature construction:
features = mf.feature_engineering.hp_filter_features(panel, columns=["CPIAUCSL"])
albama_features = mf.feature_engineering.adaptive_ma_rf_features(
panel,
columns=["CPIAUCSL"],
sided="one",
)
Leakage Boundary#
Filter |
Default fit policy |
Forecasting caution |
|---|---|---|
|
Full input, two-sided. |
Not runner-safe on an unsplit panel; use only for retrospective analysis or already training-only data. |
|
Expanding by default. |
Can be causal when |
|
Full input, centered window. |
Not runner-safe on an unsplit panel. |
|
Causal rolling approximation. |
Past-only by construction, but current implementation is not a true DWT backend. |
|
One-sided by default. |
|
AlbaMA Reference#
albama() implements the adaptive learning-based moving average from Goulet
Coulombe and Klieber (2025). The method fits a bagged tree ensemble to one
series with deterministic time as the only predictor:
y_t = f(t) + error_t
Each tree partitions the time axis into terminal-node intervals. The tree prediction is the within-leaf average, so the ensemble prediction is a learned moving average. The learned weight matrix explains the implicit look-back window at each date.
Reference:
Goulet Coulombe, Philippe, and Karin Klieber. 2025. “An Adaptive Moving Average for Macroeconomic Monitoring.” arXiv:2501.13222v1. https://arxiv.org/abs/2501.13222
R-code alignment:
R source |
Python mapping |
|---|---|
|
Manual |
|
|
|
|
|
|
The Python backend is method-aligned with the R code, but it does not promise
bit-level equality to ranger because tree split and randomization semantics
differ across backends.
Function Details#
hp_filter#
macroforecast.filters.hp_filter(
y,
*,
dates=None,
lamb=129600.0,
component="both",
interpolate_missing=True,
name=None,
) -> FilterResult
component is cycle, trend, or both. Missing values are linearly
interpolated before filtering when interpolate_missing=True.
hamilton_filter#
macroforecast.filters.hamilton_filter(
y,
*,
dates=None,
h=8,
p=4,
component="both",
fit_policy="expanding",
min_train_size=None,
missing="drop",
name=None,
) -> FilterResult
The formula is:
y[t+h] = alpha + beta_0 y[t] + ... + beta_{p-1} y[t-p+1] + error[t+h].
The trend is the fitted value and the cycle is the residual, both labeled at
t+h. fit_policy="expanding" estimates each row with earlier completed
Hamilton-regression rows. fit_policy="full_sample" reproduces the ordinary
in-sample filter style.
savitzky_golay#
macroforecast.filters.savitzky_golay(
y,
*,
dates=None,
window_length=5,
polyorder=2,
derivative=0,
interpolate_missing=True,
name=None,
) -> FilterResult
This is a centered local-polynomial smoother through
scipy.signal.savgol_filter.
wavelet_filter#
macroforecast.filters.wavelet_filter(
y,
*,
dates=None,
n_levels=3,
wavelet="db4",
name=None,
) -> FilterResult
The current implementation returns causal rolling approximation/detail columns
wA{level} and wD{level}. The wavelet argument is recorded for provenance;
it is not yet a true discrete-wavelet backend.
albama#
macroforecast.filters.albama(
y,
*,
dates=None,
mode="one_sided",
n_estimators=500,
min_samples_leaf=6,
sample_fraction=0.6,
random_state=42,
replace=True,
inbag_rule="single",
min_train_size=2,
name=None,
) -> AlbaMAResult
inbag_rule="single" mirrors the R code condition
inbag.counts[[tree]] == 1. Use macroforecast.feature_analysis to summarize
the returned weights.
stl_decompose– Seasonal-Trend decomposition using Loess (STL): trend, seasonal and remainder components (stats::stl / statsmodels STL). Two-sided full-sample.