Factor-Augmented Vector Autoregression (FAVAR) for empirical macroeconomic research
Project description
favar
favar is a Python package for estimating Factor-Augmented Vector
Autoregressive models. It is designed for empirical macroeconomic research,
monetary policy analysis, forecasting, and impulse-response analysis with large
information panels.
The package implements the two-step FAVAR procedure of Bernanke, Boivin, and Eliasz (2005). It extracts latent factors from a large panel, removes the contemporaneous policy component from the estimated factors, estimates an augmented VAR system, and projects impulse responses back to any observable series in the information panel.
Contents
- Installation
- Key Features
- Quick Start
- Model Overview
- Data Requirements
- Data Preparation and Transformations
- Slow-Moving and Fast-Moving Variables
- Estimation Procedure
- Forecasting
- Impulse Response Functions
- Residual Autocorrelation Diagnostics
- Example Summary Output
- Examples and Notebook
- Public API
- References
Installation
Install the latest release from PyPI:
pip install favar
For an editable development install from a local checkout:
pip install -e .
For development and tests:
pip install -e ".[test]"
pytest
Key Features
- Two-step FAVAR estimation following Bernanke, Boivin, and Eliasz (2005).
- Principal-component factor extraction from large information panels.
- Slow-moving variable adjustment for recursive monetary policy identification.
- Forecasts for observed variables with confidence intervals.
- Orthogonalized impulse response functions for the augmented system.
- Panel-projected impulse responses for any selected series in $X_t$.
- Lag-order selection table with AIC, BIC, FPE, and HQIC.
- Residual autocorrelation diagnostics with $2 / \sqrt{T}$ bounds.
- Clean pandas-based interface.
Quick Start
from favar import FAVAR
model = FAVAR(
X=X,
Y=Y,
policy_var="policy_rate",
k_factors=3,
slow_columns=slow_columns,
standardize=True,
)
order_selection = model.select_order(maxlags=12)
print(order_selection.summary())
results = model.fit(lags=4)
print(results.summary())
forecast = results.forecast(steps=12, confidence_level=0.95)
irf_y = results.impulse_response(periods=48, impulse_size=0.25)
irf_x = results.panel_impulse_response(
periods=48,
columns=["ip_growth", "inflation_core"],
impulse_size=0.25,
)
Model Overview
A FAVAR combines a large information panel $X_t$ with a smaller set of observed variables $Y_t$ that enter the VAR directly.
- $X_t$ is a large panel of economic indicators with dimension $T \times N$.
- $Y_t$ is a smaller set of observed variables with dimension $T \times M$.
- $F_t$ is a low-dimensional vector of latent factors extracted from $X_t$.
- $R_t$ is the policy instrument, supplied through
policy_var.
The estimated system is:
$$ \begin{aligned} Z_t &= c + A_1 Z_{t-1} + \cdots + A_p Z_{t-p} + u_t, \ X_t &= d + \Lambda F_t + \Gamma Y_t + e_t, \end{aligned} $$
where:
$$ Z_t = \begin{bmatrix} F_t \ Y_t \end{bmatrix}. $$
The policy variable is ordered last in $Y_t$ for recursive identification.
Data Requirements
Prepare two pandas DataFrame objects:
X # large information panel, shape T x N
Y # observed VAR variables, shape T x M
Both inputs must:
- have a compatible time index;
- be observed at the same frequency, such as monthly or quarterly;
- contain only numeric columns;
- contain no missing values after transformations;
- be aligned over the same sample period;
- include
policy_varas a column ofY.
Example layout:
X
ip_growth employment_growth inflation_core credit_spread
2000-01 0.31 0.12 0.22 1.21
2000-02 0.28 0.10 0.19 1.18
Y
output_growth inflation policy_rate
2000-01 0.31 0.22 5.75
2000-02 0.28 0.19 5.80
Data Preparation and Transformations
The package standardizes X internally when standardize=True, but it does
not decide the economic transformation of each raw series. Transformations
should be chosen before estimation.
Common transformations:
Log growth
For real quantities such as production, employment, credit, or monetary aggregates:
$$ \Delta \log(x_t) = 100 \left[\log(x_t) - \log(x_{t-1})\right]. $$
Inflation
For price indexes:
$$ \pi_t = 100 \left[\log(P_t) - \log(P_{t-1})\right]. $$
Interest rates and spreads
Interest rates, spreads, and percentages are often used in levels:
$$ r_t = R_t. $$
They can also be differenced when the empirical design calls for changes:
$$ \Delta r_t = r_t - r_{t-1}. $$
Practical preprocessing checklist
Before fitting the model:
- seasonally adjust series when appropriate;
- apply logs before differencing strictly positive level series;
- avoid mixing levels and growth rates without an economic reason;
- document outlier treatment and sample restrictions;
- call
dropna()after transformations; - verify that
X.index.equals(Y.index)isTrue.
Example:
import numpy as np
import pandas as pd
raw = pd.read_csv("macro_panel.csv", parse_dates=["date"]).set_index("date")
X = pd.DataFrame(index=raw.index)
X["ip_growth"] = 100 * np.log(raw["industrial_production"]).diff()
X["employment_growth"] = 100 * np.log(raw["employment"]).diff()
X["inflation_core"] = 100 * np.log(raw["core_price_index"]).diff()
X["credit_spread"] = raw["credit_spread"]
Y = pd.DataFrame(index=raw.index)
Y["output_growth"] = X["ip_growth"]
Y["inflation"] = X["inflation_core"]
Y["policy_rate"] = raw["policy_rate"]
data = pd.concat([X, Y], axis=1).dropna()
X = data[X.columns]
Y = data[Y.columns]
Slow-Moving and Fast-Moving Variables
For monetary policy applications, the information panel is divided into:
- slow-moving variables: variables assumed not to react contemporaneously to the policy shock within the period, such as output, employment, consumption, and some prices;
- fast-moving variables: variables allowed to react within the period, such as interest rates, spreads, asset prices, and financial indicators.
Pass the slow-moving columns through slow_columns:
slow_columns = [
"ip_growth",
"employment_growth",
"inflation_core",
]
If slow_columns=None, all columns in X are treated as slow-moving. This is
allowed, but explicit classification is recommended for monetary policy work.
Estimation Procedure
Let $X^s$ denote the standardized information panel:
$$ X^s_{tj} = \frac{X_{tj} - \bar{X}_j}{s_j}. $$
The implemented two-step estimator proceeds as follows.
1. Principal components from the full panel
Estimate $K$ principal components from $X^s$:
$$ \widehat{C}_t = \widehat{C}(F_t, Y_t). $$
These components estimate the common space spanned by both latent factors and observed variables.
2. Principal components from slow-moving variables
Estimate $K$ principal components from the slow-moving subset of the panel:
$$ \widehat{C}^{}_t = \widehat{C}^{}(F_t). $$
These components are used to isolate the latent factor space from the contemporaneous policy instrument.
3. Remove the contemporaneous policy component
Regress the full-panel principal components on a constant, the policy instrument, and the slow-moving principal components:
$$ \widehat{C}_t = a + b_R R_t + B_S \widehat{C}^{*}_t + v_t. $$
The cleaned factor estimate is:
$$ \widehat{F}_t = \widehat{C}_t - \widehat{b}_R R_t. $$
4. Estimate the augmented VAR
Stack the cleaned factors and observed variables:
$$ \widehat{Z}_t = \begin{bmatrix} \widehat{F}_t \ Y_t \end{bmatrix}. $$
Estimate:
$$ \widehat{Z}t = c + A_1 \widehat{Z}{t-1}
- \cdots
- A_p \widehat{Z}_{t-p}
- u_t. $$
5. Estimate the measurement equation
Estimate the relationship between the standardized information panel and the augmented state:
$$ X^s_t = d + \Theta \widehat{Z}_t + e_t. $$
This measurement equation allows responses from the FAVAR system to be mapped back to each series in $X$:
$$ \operatorname{IRF}{X}(h) = \operatorname{IRF}{Z}(h)\widehat{\Theta}. $$
When scale="original", projected panel responses are multiplied by the
stored standard deviation of each original X column.
Basic Usage
from favar import FAVAR
model = FAVAR(
X=X,
Y=Y,
policy_var="policy_rate",
k_factors=3,
slow_columns=slow_columns,
standardize=True,
)
results = model.fit(lags=13)
print(results.summary())
Main arguments:
X: large information panel.Y: observed variables included directly in the FAVAR system.policy_var: policy instrument column inY.k_factors: number of latent factors.slow_columns: slow-moving columns fromX.standardize: whether to standardizeXbefore factor extraction.lags: fixed lag order for the augmented VAR.
Lag order can also be selected by an information criterion:
order_selection = model.select_order(maxlags=12)
print(order_selection.summary())
results = model.fit(select_order="aic", maxlags=12)
Accepted criteria are "aic", "bic", "hqic", and "fpe".
Compact order-selection example:
FAVAR Lag Order Selection (* highlights the minimums)
==================================
AIC BIC FPE HQIC
----------------------------------
0 -1.262 -1.208 0.2832 -1.240
1 -3.985* -3.769* 0.01859* -3.897*
2 -3.979 -3.601 0.01870 -3.826
3 -3.927 -3.386 0.01971 -3.708
4 -3.881 -3.178 0.02066 -3.596
----------------------------------
Forecasting
Use forecast() to forecast the observed variables in Y:
forecast = results.forecast(steps=12, confidence_level=0.95)
print(forecast.head())
For each variable in Y, the output includes:
- point forecast;
- lower confidence bound;
- upper confidence bound.
Example column names:
policy_rate policy_rate_lower policy_rate_upper
Impulse Response Functions
Use impulse_response() for responses of the augmented FAVAR system.
irf_system = results.impulse_response(
periods=48,
shock="policy_rate",
impulse_size=0.25,
include_factors=False,
)
print(irf_system.head())
impulse_size=0.25 rescales the shock so that the impact response of the
policy variable is 0.25. If the policy rate is measured in percentage
points, this corresponds to 25 basis points.
Use panel_impulse_response() to project responses back to selected series in
the information panel:
irf_panel = results.panel_impulse_response(
periods=48,
shock="policy_rate",
columns=["ip_growth", "inflation_core", "credit_spread"],
scale="original",
impulse_size=0.25,
)
print(irf_panel.head())
Use:
scale="original"for projected responses in the transformed units supplied by the user;scale="std"for responses in standardized panel units.
Residual Autocorrelation Diagnostics
Use plot_acorr() to inspect residual autocorrelations and cross-correlations
of the augmented FAVAR system:
fig = results.plot_acorr(nlags=10)
The figure contains one panel for each pair of variables in the augmented system. The dashed bands are $2 / \sqrt{T}$ bounds.
Example Summary Output
results.summary() returns a text summary with overall fit statistics,
equation-by-equation coefficients, residual correlations, and FAVAR-specific
metadata.
Compact example:
Summary of FAVAR Regression Results
======================================
Model: FAVAR
Estimator: Two-step PCA
VAR method: OLS
Date: Sun, 28, Jun, 2026
Time: 21:14:27
--------------------------------------------------------------------
No. of Equations: 3 BIC: -3.59224
Nobs: 178 HQIC: -3.81539
Log likelihood: -383.59539 FPE: 0.01892
AIC: -3.96762 Det(Omega_mle): 0.01685
--------------------------------------------------------------------
FAVAR Model Information
====================================================================
No. of factors: 2
No. of X variables: 40
No. of observed Y variables: 1
No. of slow-moving variables: 20
Policy variable: FFR
Policy position: 3
Lag order: 2
Standardized X: True
PC variance shares: 0.579, 0.248
--------------------------------------------------------------------
Identification: recursive policy shock with the policy variable ordered last.
Results for equation F1
============================================================================
coefficient std. error t-stat prob
----------------------------------------------------------------------------
const 0.024340 0.040805 0.596496 0.551
L1.F1 0.699803 0.078694 8.892735 0.000
L1.F2 0.055353 0.068085 0.813003 0.416
L1.FFR -0.001386 0.028840 -0.048049 0.962
...
Correlation matrix of residuals
F1 F2 FFR
F1 1.000000 -0.266766 -0.145655
F2 -0.266766 1.000000 0.674814
FFR -0.145655 0.674814 1.000000
Examples and Notebook
Run the self-contained script:
python examples/synthetic_demo.py
Open the walkthrough notebook:
notebooks/favar_synthetic_walkthrough.ipynb
The notebook demonstrates:
- package import and installation check;
- synthetic macroeconomic data generation;
- preprocessing and transformations;
- construction of
X,Y, andslow_columns; - FAVAR estimation;
- forecasts with confidence intervals;
- impulse response functions;
- panel-projected impulse responses.
Public API
from favar import FAVAR
Main methods:
FAVAR(...).fit(...): estimate the model.results.summary(): print the estimation summary.model.select_order(maxlags=12): compare lag orders by information criteria.results.forecast(steps, confidence_level=0.95): forecast observed variables.results.impulse_response(periods, impulse_size=None): compute system IRFs.results.panel_impulse_response(periods, columns=None): compute IRFs projected to the information panel.results.plot_acorr(nlags=10): plot residual autocorrelations and cross-correlations.results.is_stable(): check dynamic stability of the augmented VAR.
Final Checklist Before Estimation
XandYhave the same time index.- No missing values remain after transformations.
- All columns in
XandYare numeric. policy_varis a column ofY.- Every item in
slow_columnsis a column ofX. k_factors <= min(T, N).- The lag order is feasible for the available sample size.
- Transformations are economically justified and documented.
References
Bernanke, B. S., Boivin, J., & Eliasz, P. (2005). Measuring the Effects of Monetary Policy: A Factor-Augmented Vector Autoregressive (FAVAR) Approach. Quarterly Journal of Economics.
Lutkepohl, H. (2005). New Introduction to Multiple Time Series Analysis. Springer.
Seabold, S., & Perktold, J. (2010). statsmodels: Econometric and Statistical Modeling with Python. Proceedings of the 9th Python in Science Conference.
License
MIT.
Project details
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 favar-0.1.0.tar.gz.
File metadata
- Download URL: favar-0.1.0.tar.gz
- Upload date:
- Size: 25.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0afbf62d5eff61a195a7eaf3ce019ab05864c571e25a6e0d730f0ad7fce0a922
|
|
| MD5 |
d22a3aa52f26643665641009b19d9127
|
|
| BLAKE2b-256 |
09d4f79b4a13246a9a64c4f5386cd330d55d9844569d9c5e93b904015c36d5f2
|
File details
Details for the file favar-0.1.0-py3-none-any.whl.
File metadata
- Download URL: favar-0.1.0-py3-none-any.whl
- Upload date:
- Size: 18.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
30d4b38d82362dba7b7ebd856467a9cb690f4e9b46973426a7457e6903f505f7
|
|
| MD5 |
0dfc0f47c4243965197c5ab11887c020
|
|
| BLAKE2b-256 |
7bd931dffada446d510c46d9df5022d33d10f592776a7d64c1caa7edf19ababa
|