deeppanel
Deep neural network estimation, forecasting and inference in panel data models.
📦 PyPI: https://pypi.org/project/deeppanel/ — pip install deeppanel
deeppanel is a faithful Python implementation of three recent papers on deep
learning for panel data:
| Estimator | Paper |
|---|---|
DeepPooledPanel (+ poolability test, partial derivatives, benchmarks) |
Chronopoulos, Chrysikou, Kapetanios, Mitchell & Raftapostolos, Deep Neural Network Estimation in Panel Data Models, FRB Cleveland WP 23-15 (2023); Forecasting with Deep Pooled Panel Neural Networks, Econometric Reviews (2026). |
LDPM (surrogate augmentation, homogeneity pursuit, conformal intervals) |
Gao, Sun, Wang, Liu & Hsiao, How Does LLM Help Regional CPI Forecast: An LLM-powered Deep Panel Modeling Framework (2026). |
Every estimator is checked equation-by-equation against its source and validated
on the papers' own known-truth simulation designs — see
docs/PAPER_COMPATIBILITY.md.
Author: Dr Merwan Roudane. Licensed MIT.
Installation
pip install deeppanel # from PyPI (once published)
# or, from a local clone:
pip install -e .
Requires Python ≥ 3.9 and numpy, pandas, scipy, torch, matplotlib.
Optional extras (statsmodels, scikit-learn) install with pip install deeppanel[extras].
Quickstart
📖 Full syntax cookbook:
docs/USAGE.md— copy-paste-ready scripts for every workflow (data prep, every option, benchmarks, tables, plots, LDPM). The blocks below are the short version.
Step 0 — build a balanced panel
Every estimator takes a PanelData: y is (N, T), X is (N, T, p)
(N units, T periods, p regressors).
import numpy as np
from deeppanel import PanelData
# (a) from NumPy arrays
panel = PanelData(
y, # shape (N, T)
X, # shape (N, T, p)
units=["CA","FR","DE","IT","JP","UK","US"], # optional labels
feature_names=["unemp","core_cpi","energy"], # optional
)
# (b) from a long/tidy pandas DataFrame (one row per unit-period)
panel = PanelData.from_long(df, unit="country", time="year",
y="inflation", x=["unemp", "core", "energy"])
print(panel) # PanelData(N=7, T=80, p=3)
1. Deep pooled panel forecasting (Chronopoulos et al.)
from deeppanel import DeepPooledPanel, TrainConfig
model = DeepPooledPanel(
horizon=4, # direct h-step forecasting: y_it ~ x_{i,t-h}
depth=3, width=20, # L hidden ReLU layers of width M (or pass cv=PAPER_GRID)
idiosyncratic=False, # add per-unit component h_i (WP Eq. 10) if True
feature_scale="standardize",
config=TrainConfig(max_epochs=1000, lr=0.01, batch_size=14, seed=0),
seed=0,
)
model.fit(panel)
yhat = model.forecast(panel) # (N,) one direct h-step forecast per unit
print(dict(zip(panel.units, np.round(yhat, 3))))
# Interpretability & diagnostics:
grad = model.partial_derivatives(panel.X[:, -1, :]) # (N, p) marginal effects (Eq. 11)
test = model.poolability_test(panel) # need a unit-specific component?
print(f"poolability P={test.statistic:.2f}, p={test.p_value:.3f}")
2. Compare against benchmarks (recursive out-of-sample)
from deeppanel import rolling_forecast, viz
from deeppanel.benchmarks import DeepTimeSeries, PanelVAR, ARBenchmark
cfg = TrainConfig(max_epochs=500, lr=0.01, batch_size=14, seed=0)
models = {
"DeepPooled": lambda: DeepPooledPanel(horizon=1, depth=3, width=20, config=cfg, seed=0),
"DeepTS": lambda: DeepTimeSeries(horizon=1, depth=3, width=20, config=cfg, seed=0),
"PVAR": lambda: PanelVAR(max_lags=4),
"AR1": lambda: ARBenchmark(1),
}
res = rolling_forecast(panel, models, horizon=1, start_frac=0.7)
rmse = {n: res.rmse(n) for n in models}
ratios = {n: rmse[n] / rmse["AR1"] for n in models}
pvals = res.dm_table(base="AR1").set_index("model")["p_value"].to_dict()
print(viz.forecast_table(rmse, ratios=ratios, pvalues=pvals, base="AR1")) # journal table
3. LLM-powered Deep Panel Modeling (Gao et al.)
from deeppanel import LDPM, surrogate_residuals
# The LLM/BERT text pipeline is external; feed its aggregated outputs here.
# y:(N,T) X:(N,T,dx) embeddings Z:(N,T,dz) macro y_surr:(N,T) x_surr:(N,T,ds)
eps_S = surrogate_residuals(y_surr, x_surr, n_lags=1) # Eq. 3.2 residuals
ldpm = LDPM(n_groups=3, lam=0.05, alpha=0.10, seed=0)
ldpm.fit(y[:, :-1], X[:, :-1], Z=Z[:, :-1], surrogate_resid=eps_S[:, :-1], calibrate=True)
groups = ldpm.groups # latent groups (C-LASSO)
yhat, lower, upper = ldpm.forecast_interval(X[:, -1, :], Z_last=Z[:, -1, :],
surrogate_resid_last=eps_S[:, -1]) # conformal
What's implemented
Deep pooled panel (Papers 2 & 3)
DeepPooledPanel— pooled MSE estimator of the common componenth(Eq. 9), optional idiosyncratic componenth_i(Eq. 10); ReLU MLP with linear output (Eq. 16); LASSO penalty; ADAM, dropout, batch-norm, early stopping.cross_validate/PAPER_GRID— data-driven selection of depthL, widthM, learning rate, and LASSOλ = c√(log p / NT)over the paper's grids.partial_derivatives— exact∂g/∂xvia autograd (Eq. 11).poolability_test— nonlinear test ofh̃_i = h(Remark 3).- Benchmarks:
ARBenchmark,PanelVAR(BIC lags, iterated),LinearPooledPanel(LPM/LPM-E),DeepTimeSeries(pooling switched off). - Evaluation:
diebold_mariano,fluctuation_test(Giacomini–Rossi),rmse/pmse. rolling_forecast— recursive expanding-window OOS harness producing RMSE-ratio tables and DM comparisons.
LDPM (Paper 1)
surrogate_residuals— the surrogate modelG_iand its residuals (Eq. 3.2).LDPM— surrogate-augmented target model (Eqs. 3.1–3.4) fit by Deep Panel Training with classifier-LASSO homogeneity pursuit (Eqs. 3.5–3.7) recovering latent groups, plus within-group split-conformal intervals (§3.4).DeepPanelTraining— the standalone homogeneity-pursuit estimator.svd_reduce,max_pool,mean_pool— the embedding reduction/aggregation of §4.1 / App. A.2.
Visualization (deeppanel.viz) — journal-style tables (forecast_table,
coef_table, to_latex) and figures (plot_forecasts, plot_partial_derivatives,
plot_conformal_intervals, plot_rmse_heatmap, plot_group_map), plus MATLAB
colour maps (parula_colors, …) with Parula as the default.
Syntax reference
Every argument of every function, with runnable examples, is in the usage cookbook →
docs/USAGE.md. Quick method summary below.
DeepPooledPanel(horizon=1, depth=3, width=20, idiosyncratic=False, demean=True, feature_scale="standardize", target_scale="none", cv=None, val_frac=0.2, config=None, first_layer_bias=False, batchnorm=False, dropout=0.0, seed=None)
| Method | Returns |
|---|---|
.fit(panel) |
fits the common (+ optional idiosyncratic) network(s) |
.predict(X, units=None) |
predictions on the original target scale |
.forecast(panel) |
direct h-step forecast per unit, (N,) |
.partial_derivatives(X, feature=None) |
∂g/∂x in original units |
.poolability_test(panel, feature_map="poly", split=False) |
PoolabilityResult(statistic, p_value, r2, ...) |
.architecture |
the selected {depth, width, lr, lambda, dropout} |
LDPM(n_groups=3, d_h=8, depth=3, width=20, lam=0.05, alpha=0.10, feature_scale="standardize", calib_frac=0.2, warmup=200, epochs=400, lr=0.01, seed=None)
| Method | Returns |
|---|---|
.fit(y, X, Z=None, surrogate_resid=None, calibrate=True) |
fits the augmented DPT model + calibrates conformal radii |
.forecast(X_last, Z_last=None, surrogate_resid_last=None) |
one-step point forecast per unit |
.forecast_interval(...) |
(yhat, lower, upper) with within-group conformal radii |
.groups |
estimated latent group labels (N,) |
See full docstrings (help(DeepPooledPanel), help(LDPM)) for every argument.
Examples
Runnable scripts in examples/ (each writes figures to examples/_output/):
python examples/01_deep_pooled_forecasting.py # RMSE table + DM vs benchmarks
python examples/02_partial_derivatives_poolability.py
python examples/03_ldpm_conformal.py # groups + conformal intervals
Example 1 prints a journal-style table such as:
Out-of-sample forecast accuracy
--------------------------------------
Model RMSE Ratio
DeepPooled 0.256 0.356***
DeepTS 0.413 0.574***
PVAR 0.733 1.019
AR1 0.719 1.000
--------------------------------------
Stars: Diebold-Mariano test vs base. *** p<.01 ** p<.05 * p<.10
Faithfulness to the papers
deeppanel reproduces the papers' theorems and headline results on their own
DGPs: Proposition 1 consistency, the pooling gain (deep pooled ≻ deep
time-series ≻ linear), correct poolability-test size and power, exact partial
derivatives, C-LASSO group recovery ≈ 0.94, split-conformal coverage ≈ nominal,
and the Table-8 result that LDPM's surrogate gain grows with the target/surrogate
error correlation. Details and the equation-by-equation map are in
docs/PAPER_COMPATIBILITY.md.
The LLM/BERT text pipeline of Paper 1 (GPT annotation, fine-tuned BERTs, LDA
/ OpenAI embeddings) is intentionally out of scope — it is inherently external.
deeppanel implements the full statistical model on top of its outputs.
Testing
pip install -e ".[dev]"
pytest -q
Citation
If you use this package, please cite the package and the underlying papers (see
CITATION.cff).
License
MIT © Merwan Roudane.
Metadata
Release files for deeppanel 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| deeppanel-0.1.2.tar.gz | 55.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| deeppanel-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 116.8 kB
Release files / deeppanel-0.1.2.tar.gz
| Download URL | deeppanel-0.1.2.tar.gz |
|---|---|
| Size | 55.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b454ee0dfa3ed292b759cefbe367a07cbef503d2f804d966a1e2b9f81370756d
|
|
BLAKE2b-256 checksum How to use checksums |
26fb50b9bc94d070af8242e9ffa3654adedfef856a6131d6e6cbbcbdc162bdfb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / deeppanel-0.1.2-py3-none-any.whl
| Download URL | deeppanel-0.1.2-py3-none-any.whl |
|---|---|
| Size | 61.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c64e80d4d2d899a855f7a7152d2f80c60ee5a25c41939ddbd1cc037edf7a35e7
|
|
BLAKE2b-256 checksum How to use checksums |
8fd669d3f4d97fec6fa2a5de9a42d3a0669a89a82c6735ea134a047be36b83c2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Security for deeppanel 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.