Features#

Back to User Guide

macroforecast.feature_engineering is the direct pandas surface for building forecast targets and model-ready feature matrices. For strict windowed forecasting, use feature_spec(...). The spec is fitted by macroforecast.forecasting.run(...) inside each train window and then transformed for the matching test rows, so stateful operations such as PCA are estimated only on estimation-window data.

The package organizes feature types into five families used across replication papers:

  • F (factors): principal component or sparse-PCA factors extracted from the full predictor set.

  • X (raw lags): lagged columns of individual series without dimension reduction.

  • MARX (moving-average lag cross): mixed lags and moving averages of each series, the standard macro predictor design used in McCracken-Ng style papers.

  • MAF (maximum autocorrelation factors): rotation of PC factors to maximize autocorrelation, useful for persistent macro series.

  • Level: raw (untransformed) level columns joined alongside the stationary predictors; assigned t-code 1 (identity) so official preprocessing passes them through unchanged.

Key Callables#

mf.feature_engineering.feature_spec stores feature construction choices for runner-fitted execution. The returned FeatureSpec is passed to forecasting.run or to an Arm.

import macroforecast as mf

# MARX lags: the default macro predictor design. The marx_step builds the
# increasing-average lag ladder over every predictor column.
marx_features = mf.feature_engineering.feature_spec(
    target="INDPRO",
    predictors="all",
    lags=None,
    feature_steps=[
        mf.feature_engineering.marx_step(name="MARX_X", max_lag=12),
    ],
)

# Pure lag features (no moving averages): lag every predictor 1..12.
lag_features = mf.feature_engineering.feature_spec(
    target="INDPRO",
    predictors="all",
    lags=range(1, 13),
)

# Factor features: extract the first k principal components, then lag them.
factor_features = mf.feature_engineering.feature_spec(
    target="INDPRO",
    predictors="all",
    lags=None,
    feature_steps=[
        mf.feature_engineering.pca_step(name="F", n_components=8, include=False),
        mf.feature_engineering.lag_step(name="F_lag", input="F", lags=range(0, 3)),
    ],
)

# MAF features: maximum autocorrelation factors.
maf_features = mf.feature_engineering.feature_spec(
    target="INDPRO",
    predictors="all",
    lags=None,
    feature_steps=[
        mf.feature_engineering.maf_step(name="MAF", n_components=8, max_lag=12),
    ],
)

Executed walkthrough#

For exploration, mf.build_features materializes a feature matrix immediately. Building the MARX ladder over all predictors on a panel slice:

sl = bundle.panel.loc["1960-01":"2000-12"]
fs = mf.build_features(
    sl, target="INDPRO", predictors="all", lags=None,
    feature_steps=[mf.feature_engineering.marx_step(name="MARX_X", max_lag=12)],
)
print(type(fs).__name__, fs.X.shape)
print(list(fs.X.columns[:6]))
FeatureSet (94, 1524)
['RPI_ma1_lag1', 'RPI_ma2_lag1', 'RPI_ma3_lag1', 'RPI_ma4_lag1', 'RPI_ma5_lag1', 'RPI_ma6_lag1']

The 1524 columns are the 127 predictors each expanded into a 12-step moving-average lag ladder. The row count is reduced because drop_missing=True removes rows with any gap in the raw slice. Feature engineering works best on a PreprocessedData panel from reprocess, which fills those gaps before the ladder is built. Inside a runner, feature_spec fits these same steps on each train window so that stateful operations such as PCA never see test rows.

Reference#