Model card — Panel time series¶
Family: panel_fe, panel_lp, mean_group_var, panel_mean_group,
panel_pmg
Many entities, each observed over time. The methods here span the two ends of
the panel spectrum: pooled estimators that assume a common slope and
difference out fixed effects (panel_fe, panel_lp), and heterogeneous
estimators that let every unit have its own dynamics and then average or pool
carefully across them (mean_group_var, panel_mean_group, panel_pmg). The
recurring theme is honest inference: cross-sectional and serial correlation
both bias naïve standard errors, so the defaults reach for Driscoll-Kraay and
cluster covariances.
| Function | Slope assumption | Delivers |
|---|---|---|
panel_fe |
common | Fixed-effects OLS with robust SEs |
panel_lp |
common | Panel local-projection IRF of a common shock |
mean_group_var |
heterogeneous | Mean-group panel VAR + orthogonalized IRFs |
panel_mean_group |
heterogeneous | Mean-group / CCE-MG average slope |
panel_pmg |
pooled long run, free short run | Pooled Mean Group ARDL(1,1) |
What it estimates¶
panel_fe(outcome, regressors)— the within (fixed-effects) estimator: entity means are swept out and a common slope vector is estimated by OLS, with clustered or Driscoll-Kraay standard errors.outcomeis N×T;regressorsis k×N×T.panel_lp(outcome, shock)— a panel local projection: at each horizon h, regress the h-step-ahead outcome on a common shock with entity fixed effects, tracing a dynamic causal response averaged across units.mean_group_var(entities)— fits a separate VAR to each entity's Tᵢ×k matrix and averages the coefficients and orthogonalized IRFs (Pesaran-Smith 1995). Robust to slope heterogeneity that a pooled panel VAR would bias.panel_mean_group(ys, xs)— the mean-group estimator: per-unit OLS slopes averaged across units, with the cross-unit standard deviation giving the standard error.method="cce"adds Pesaran (2006) common-correlated- effects terms (cross-sectional averages) to purge a common factor.panel_pmg(ys, xs)— the Pooled Mean Group ARDL(1,1) estimator (Pesaran-Shin-Smith 1999): the long-run coefficient θ is pooled (common across units) by maximum likelihood, while the error-correction speed and short-run dynamics stay unit-specific.
Assumptions¶
panel_fe/panel_lpassume a common slope. If the true response differs across units, the pooled estimate is a variance-weighted average that need not equal the cross-sectional mean effect — reach for the mean-group estimators instead.- Cross-sectional dependence. With a common shock or common factor, errors
are correlated across entities at each date; cluster-by-entity SEs do not
address this.
se_type="driscoll_kraay"is the default forpanel_lpprecisely because it is robust to both serial and cross-sectional correlation. panel_pmgrequires a genuine ARDL / error-correction structure: the long-run regressors must be non-degenerate and not collinear across the panel once short-run dynamics are partialled out, or θ is not identified (the estimator raises rather than returning a meaningless number). Feed it level series with real dynamics, not, say, a shock and its own lag.- Mean-group estimators need enough time per unit to estimate each unit's regression; they trade the efficiency of pooling for robustness to heterogeneity, and are noisy when Tᵢ is small.
panel_mean_group(method="mg")is a static regression of y on contemporaneous x — its average slope is not the ARDL long-run coefficient. Usepanel_pmgwhen the object of interest is a common long-run relationship.
When to use¶
panel_fe— the workhorse when you believe in a common slope and want clustered or Driscoll-Kraay inference (e.g. the effect of a policy variable across countries).panel_lp— dynamic causal responses to a common shock (a global oil or monetary shock hitting many countries), fixed effects for level differences, Driscoll-Kraay bands.mean_group_var— impulse responses in a heterogeneous panel where a pooled VAR would be misspecified.panel_mean_group— the average marginal effect across heterogeneous units;method="cce"when an unobserved common factor contaminates OLS.panel_pmg— long-run equilibrium relationships (growth-savings, consumption-income) where theory says the long run is common but adjustment speeds differ by country.
Key arguments and defaults¶
| Call | Argument | Default | Notes |
|---|---|---|---|
panel_fe |
se_type |
"cluster" |
"nonrobust", "cluster" (by entity), "driscoll_kraay" |
bandwidth |
4.0 |
Driscoll-Kraay kernel bandwidth | |
panel_lp |
horizon |
8 |
IRF horizons |
n_lag_controls |
2 |
lags of outcome/shock included as controls | |
se_type |
"driscoll_kraay" |
robust to cross-sectional dependence | |
cumulative |
False |
True for cumulative IRFs |
|
jackknife |
False |
leave-one-entity-out bias reduction | |
mean_group_var |
lags |
1 |
per-entity VAR order |
trend |
"c" |
deterministic terms | |
horizon / response / impulse |
10 / 0 / 0 |
IRF horizon and the response/shock variable indices | |
panel_mean_group |
method |
"mg" |
or "cce" (common-correlated-effects) |
panel_pmg |
— | — | ys/xs per-unit level series and Tᵢ×k regressor matrices |
How to read the output¶
panel_fe→{"params", "bse", "tvalues", "se_type"}, one entry per regressor. The stampedse_typetells you which covariance producedbse.panel_lp→{"irf", "se", "nobs"}, each lengthhorizon+1; plotirf±1.96·se.irf[0]is the impact response.mean_group_var→ per-entity-averagedintercept,coefs(lags × neqs × neqs) and their SEs, plusorth_irfs(horizon+1 × response × shock) with SEs and a convenienceirf_path(theresponse/impulsecell) andirf_path_se. Alson_entities,neqs,lags.panel_mean_group→{"coef", "se", "tstat", "coef_per_unit", "n_units", "k"}.coef_per_unit(n_units × k) lets you inspect the spread of individual slopes behind the average.panel_pmg→{"theta", "theta_se", "phi_bar", "phi", "sigma2", "loglik", "iterations", "n_units", "k"}.thetais the pooled long-run coefficient;phi_baris the average error-correction speed (negative and bounded by −1 for stable adjustment);phiis the per-unit speed vector.
Failure modes¶
- Pooling heterogeneous slopes.
panel_feon data with genuinely different unit responses returns a hard-to-interpret weighted average. If a Hausman-style comparison of pooled vs mean-group estimates diverges, trust the mean-group one. - Cluster SEs under cross-sectional dependence. With a common shock,
se_type="cluster"understates uncertainty. Usedriscoll_kraay. panel_pmgcollinearity error. If the partialled long-run regressors are collinear across the panel, θ is unidentified and the call raises. This is a correct refusal, not a bug — supply level regressors with real, non-redundant long-run variation.- Small Tᵢ with mean-group. Per-unit regressions become unstable and the cross-unit average inherits the noise; prefer pooling (with heterogeneity tested) when time series are short.
- Reading
panel_mean_group(method="mg")as a long run. It is a static average slope; the ARDL long run comes frompanel_pmg.
Validated against¶
panel_fe matches linearmodels PanelOLS for the within estimator under
nonrobust, cluster-by-entity, and Driscoll-Kraay (Bartlett kernel) covariances.
panel_lp is a documented-formula golden built on the same within-plus-DK
machinery with a known simulated IRF. mean_group_var, panel_mean_group
(MG and CCE-MG), and panel_pmg are documented-formula goldens reproducing the
Pesaran-Smith (1995), Pesaran (2006), and Pesaran-Shin-Smith (1999)
estimating equations, and are additionally property-validated: on data with a
known common long run, PMG recovers it and pools far more tightly than a free
mean-group of per-unit long runs. Fixtures:
fixtures/panel.json,
fixtures/tsecon-panelts.json,
fixtures/pmg.json.
References¶
- Pesaran, M. H. & Smith, R. (1995). "Estimating long-run relationships from dynamic heterogeneous panels." J. Econometrics 68.
- Pesaran, M. H., Shin, Y. & Smith, R. (1999). "Pooled Mean Group Estimation of Dynamic Heterogeneous Panels." JASA 94.
- Pesaran, M. H. (2006). "Estimation and Inference in Large Heterogeneous Panels with a Multifactor Error Structure." Econometrica 74.
- Driscoll, J. & Kraay, A. (1998). "Consistent Covariance Matrix Estimation with Spatially Dependent Panel Data." Rev. Econ. Stat. 80.
- Jordà, Ò. (2005). "Estimation and Inference of Impulse Responses by Local Projections." AER 95.
See the guide: Panel Time Series.
Runnable example¶
import numpy as np
import tsecon
rng = np.random.default_rng(88)
N, T = 20, 100
# ---- a balanced panel with entity fixed effects and a common observed shock ----
shock = rng.standard_normal(T)
alpha = rng.normal(0, 2.0, N) # entity fixed effects
psi = 0.8 * 0.6 ** np.arange(8) # true dynamic response to the shock
y = np.empty((N, T))
for i in range(N):
u = np.empty(T); u[0] = rng.standard_normal()
for t in range(1, T):
u[t] = 0.3 * u[t - 1] + rng.standard_normal()
y[i] = alpha[i] + np.convolve(shock, psi)[:T] + u + 0.3 * rng.standard_normal(T)
# 1. Fixed-effects panel OLS. outcome is N x T; regressors is k x N x T.
s0 = np.tile(shock, (N, 1))
s1 = np.tile(np.r_[0.0, shock[:-1]], (N, 1))
regressors = np.stack([s0, s1]) # 2 x N x T
fe = tsecon.panel_fe(y, regressors, se_type="driscoll_kraay")
print("FE params:", np.round(fe["params"], 3), " (Driscoll-Kraay SEs)")
# 2. Panel local projection of the common shock (dynamic causal response).
plp = tsecon.panel_lp(y, shock, horizon=8, se_type="driscoll_kraay")
print("panel-LP IRF h=0..2:", np.round(plp["irf"][:3], 3))
# 3. Mean-group panel VAR (Pesaran-Smith): per-entity VARs, averaged.
entities = [np.column_stack([y[i], np.r_[0.0, shock[:-1]]]) for i in range(N)]
mg = tsecon.mean_group_var(entities, lags=2, horizon=8)
print("MG-VAR orthogonalized IRF path h=0..2:", np.round(mg["irf_path"][:3], 3))
# ---- a heterogeneous ARDL(1,1) panel with a COMMON long run (for MG / PMG) ----
theta0 = np.array([1.5, -0.8])
def sim_unit():
lam = rng.uniform(0.2, 0.7); mu = rng.normal(0.5, 1.0)
d0 = rng.normal([0.6, -0.3], [0.25, 0.25]); d1 = theta0 * (1 - lam) - d0
burn, tt = 50, 90 + 50; K = 2
x = np.empty((tt, K)); rho = rng.uniform(0.3, 0.6, K); xm = rng.normal(0, 1, K); x[0] = xm
for t in range(1, tt):
x[t] = xm * (1 - rho) + rho * x[t - 1] + rng.normal(0, 1, K)
yy = np.empty(tt); yy[0] = mu / (1 - lam)
for t in range(1, tt):
yy[t] = mu + lam * yy[t - 1] + d0 @ x[t] + d1 @ x[t - 1] + rng.normal(0, 0.5)
return yy[burn:], x[burn:]
ys = []; xs = []
for _ in range(25):
yy, xx = sim_unit(); ys.append(yy); xs.append(xx)
# 4. Mean-group / CCE-MG estimator: the average of per-unit static slopes.
# (A static contemporaneous regression, so this is NOT the ARDL long run.)
mgest = tsecon.panel_mean_group(ys, xs, method="mg")
print("MG average slope:", np.round(mgest["coef"], 3), " t:", np.round(mgest["tstat"], 2))
# 5. Pooled Mean Group: pool the long-run coefficient, keep short-run dynamics
# free. This IS the estimator that targets the common long run of the DGP.
pmg = tsecon.panel_pmg(ys, xs)
print("PMG long-run theta:", np.round(pmg["theta"], 3),
" (true", theta0, "), adjustment speed phi_bar:", round(pmg["phi_bar"], 3))
Expected output: