Panel data: random intercepts, fixed effects, and the Mundlak device

Benjamin E. Bagozzi

Most applications of the inflated ordered models are panels – country-years, agreement-years, campaign-years – and every estimator in iop offers the same four ways of handling unit heterogeneity:

Tool What it does Use when
cluster = "unit" cluster-robust standard errors, point estimates unchanged always sensible as a baseline
re = "unit" a unit random intercept integrated out by adaptive quadrature the unit effect is uncorrelated with the covariates
mundlak() + re = or cluster = unit means of the covariates (correlated random effects) the unit effect may be correlated with the covariates; short panels
fe = "unit" a dummy per unit (with fe_correction = "jackknife") long panels

The package’s Monte Carlo, summarized at the end, is the reason for the “use when” column.

Cluster-robust standard errors

cluster = names a column and switches se to "cluster"; the point estimates are those of the pooled model.

library(iop)
data(bp)
f <- violence ~ loggdppc + parliament + disaster | loggdppc + parliament + disaster
m_pool <- iop(f, data = bp, inflate = "bottom")
m_cl   <- iop(f, data = bp, inflate = "bottom", cluster = "country")
round(cbind(estimate = coef(m_pool), se_iid = sqrt(diag(vcov(m_pool))),
            se_cluster = sqrt(diag(vcov(m_cl)))), 3)
#>                      estimate se_iid se_cluster
#> loggdppc                0.005  0.056      0.170
#> parliament             -0.085  0.172      0.392
#> disaster                0.269  0.033      0.059
#> none|repression         0.519  0.407      1.231
#> repression|civil war    1.411  0.416      1.259
#> infl_(Intercept)       19.411  3.515      4.819
#> infl_loggdppc          -2.123  0.376      0.492
#> infl_parliament        -0.427  0.374      0.751
#> infl_disaster          -0.120  0.141      0.249

A nonparametric bootstrap is the other route: se = "bootstrap" refits the model nboot times on resamples of the clusters (when cluster = is given), of the random-intercept units, or of the rows, keeps the replicate estimates in $boot, and confint(type = "percentile") then gives percentile intervals. Dale and Sirchenko (2021) find it better calibrated than the asymptotic standard errors for the error correlation of the correlated models in small samples. It costs nboot refits (cores = parallelizes them), so it is not run here:

m_boot <- iop(f, data = bp, inflate = "bottom", se = "bootstrap", cluster = "country",
              nboot = 200, cores = 4)
confint(m_boot, type = "percentile")

Random intercepts

re = "unit" adds a normal random intercept to the outcome equation and integrates it out by adaptive Gauss–Hermite quadrature (nAGQ nodes per unit; the default 15 is accurate for the panels in this package, and fewer nodes can leave the fit short of a clean optimum, which the fit reports).

m_re <- oprobit(violence ~ loggdppc + parliament + disaster, data = bp, re = "country")
m_re
#> Ordered probit, random intercept by country 
#> Response levels (in order): none < repression < civil war 
#> Call:  oprobit(formula = violence ~ loggdppc + parliament + disaster, 
#>     data = bp, re = "country")
#> 
#> Outcome coefficients:
#>   loggdppc parliament   disaster 
#>    -0.4874    -1.0941     0.1132 
#> 
#> Cutpoints:
#>      none|repression repression|civil war 
#>              -3.0180              -1.6385 
#> 
#> Random-intercept SD: 1.3052  over 113 units
#> 
#> logLik: -1077.82   N: 1984

The same fit from ordinal::clmm(violence ~ loggdppc + parliament + disaster + (1 | country), link = "probit", nAGQ = 15) has log-likelihood -1077.816 and random-intercept SD 1.306, which is what iop reports; the package’s tests check this agreement on simulated panels. ranef() returns the empirical-Bayes unit effects:

head(ranef(m_re), 4)
#>          unit          u      u_sd
#> 1 Afghanistan  0.4995294 0.4238394
#> 2    Albania  -1.2891857 0.6875121
#> 3    Algeria   0.4122190 0.2640184
#> 4      Angola  1.0791696 0.3109542

Reported probabilities and first differences are marginal over the random intercept (population-averaged); type = "prob_conditional" gives the probabilities for a unit with a zero intercept:

head(cbind(marginal = predict(m_re)[, "civil war"],
           conditional = predict(m_re, type = "prob_conditional")[, "civil war"]), 3)
#>        marginal conditional
#> [1,] 0.03423599 0.001369266
#> [2,] 0.05203033 0.003762048
#> [3,] 0.03249352 0.001205750

Random intercepts work identically for iop() and iol(), where re_inflation = TRUE also gives the inflation equation an independent unit intercept (two-dimensional quadrature). A fit whose random-intercept SD goes to zero is flagged as a boundary case; see vignette("model").

Unit fixed effects

fe = "unit" adds a dummy per unit to the outcome equation (and, with fe_inflation = TRUE, to the inflation equation). Two things happen automatically:

m_fe <- oprobit(violence ~ loggdppc + disaster, data = bp, fe = "country")
#> 37 of 113 units have no within-unit variation that identifies their fixed effect (response constant at an extreme category); their 579 observations are dropped.
m_fe
#> Ordered probit 
#> Response levels (in order): none < repression < civil war 
#> Call:  oprobit(formula = violence ~ loggdppc + disaster, data = bp, 
#>     fe = "country")
#> 
#> Outcome coefficients:
#> loggdppc disaster 
#>  -0.4947   0.0920 
#> (75 unit fixed-effect dummies by country not shown; see coef())
#> 
#> Cutpoints:
#>      none|repression repression|civil war 
#>              -3.6579              -2.2147 
#> 
#> logLik: -905.57   N: 1405

A covariate that does not vary within units is collinear with the dummies and is refused with a message naming it – parliament, which changes in only one country of this panel, is the example here:

oprobit(violence ~ loggdppc + parliament + disaster, data = bp, fe = "country")
#> Error: Covariate(s) parliament do not vary within the units of 'country' on the
#> estimation rows and are collinear with the unit fixed effects. Drop them from the
#> outcome equation, or keep them with re = "country" or mundlak() instead of fe =.

The split-panel jackknife

fe_correction = "jackknife" applies the split-panel jackknife of Dhaene and Jochmans (2015): the model is refit on the first and second half of every unit’s observations (ordered by time), and the common parameters are bias-corrected as 2 * full - (half1 + half2) / 2. On a simulated short panel (T = 8, so the fit issues its short-panel warning) with a covariate correlated with the unit effect, the correction removes most of the incidental-parameters bias:

set.seed(42)
G <- 100; Tn <- 8
alpha <- rnorm(G); unit <- rep(1:G, each = Tn)
x1 <- rnorm(G * Tn) + 0.5 * alpha[unit]; x2 <- rnorm(G * Tn)
ystar <- 0.8 * x1 - 0.5 * x2 + alpha[unit] + rnorm(G * Tn)
d <- data.frame(y = findInterval(ystar, c(-1, 0.3, 1.2)), x1, x2, unit, t = rep(1:Tn, G))
m_jk <- oprobit(y ~ x1 + x2, data = d, fe = "unit", fe_correction = "jackknife", time = "t")
#> Warning in .iord_fit(formula, data, link, inflate, correlated, parallel, : Unit
#> fixed effects with few observations per unit (median 8): maximum-likelihood
#> dummies carry incidental-parameters bias in nonlinear models (Greene 2004);
#> consider re = "unit" or mundlak() with cluster = "unit".
rbind(uncorrected = m_jk$coefficients_uncorrected[c("x1", "x2")],
      jackknife   = coef(m_jk)[c("x1", "x2")],
      truth       = c(0.8, -0.5))
#>                    x1         x2
#> uncorrected 1.0148638 -0.6726296
#> jackknife   0.8556086 -0.5460368
#> truth       0.8000000 -0.5000000

The reported covariance after the correction is the full-sample one: Dhaene and Jochmans (2015) show that the split-panel jackknife removes the leading bias without changing the first-order asymptotic variance, so it is the asymptotically valid covariance for the corrected estimator (summary() says so); in finite samples the corrected estimator is somewhat noisier, so treat its intervals as approximate. A computational note: the dummies enter the parameter vector one per unit, and the exact-Hessian steps cost roughly the square of the parameter count (about 0.5 s at 20 units, 3 s at 100, 18 s at 300 for an ordered probit on 4,000 rows, more for an inflated model’s multistart), so for panels with many hundreds of units prefer re = or mundlak(). The correction is only as good as the two half-panel fits, which are stored in m_jk$jackknife. When a covariate is identified mainly by a within-unit trend – as log GDP per capita is in bp, where 99 percent of its within-country variation is linear in time – the half-panels barely identify it, their estimates are far from the full-sample one, and the “correction” inherits that noise. Inspect the half-panel coefficients before reporting a jackknifed estimate:

m_jk$jackknife$half_coefficients[, c("x1", "x2")]
#>             x1         x2
#> half1 1.324288 -0.8560121
#> half2 1.023950 -0.7424329

The Mundlak device

mundlak() augments the data with the unit means of the time-varying numeric covariates of both equations and returns the augmented formula and data. Any estimator fit on the result implements the correlated-random-effects specification: the coefficients on the original covariates are the within-unit effects, and the coefficients on the unit means capture – and test – the correlation between the covariates and the unit effect. It pairs naturally with cluster-robust standard errors or a random intercept, and it keeps time-invariant covariates estimable.

md <- mundlak(violence ~ loggdppc + parliament + disaster | loggdppc + parliament + disaster,
              data = bp, unit = "country")
md$formula
#> violence ~ loggdppc + parliament + disaster + loggdppc_mean + 
#>     parliament_mean + disaster_mean | loggdppc + parliament + 
#>     disaster + loggdppc_mean + parliament_mean + disaster_mean
md$added
#> [1] "loggdppc_mean"   "parliament_mean" "disaster_mean"
m_md <- oprobit(violence ~ loggdppc + parliament + disaster + loggdppc_mean + disaster_mean,
                data = md$data, cluster = "country")
round(summary(m_md)$coefficients[, 1:2], 3)
#>                      Estimate Std. Error
#> loggdppc               -0.263      0.326
#> parliament             -0.610      0.345
#> disaster                0.052      0.028
#> loggdppc_mean           0.057      0.338
#> disaster_mean           0.323      0.115
#> none|repression        -0.954      0.776
#> repression|civil war   -0.099      0.794

(The unit mean of parliament is not added to the outcome equation above because it is time-invariant in all but one country, so its mean would be nearly collinear with the variable itself.)

The Monte Carlo: which device for which panel

system.file("mc", package = "iop") holds a Monte Carlo (fe_bias.R) that compares the four devices on an ordered probit with G = 100 units, a N(0, 1) unit effect, and a covariate correlated with it (x1 = N(0,1) + 0.5 * alpha), for T = 4, 8, 16, 32 and 100 replications, together with an audit script (fe_bias_verify.R) that checks the pooled bias against its closed form and each estimator against ordinal::clm() / clmm() on identical draws. The percent bias of the x1 coefficient (true value 0.8):

Percent bias of the x1 coefficient, 100 replications per cell
estimator T = 4 T = 8 T = 16 T = 32
pooled +11.9 +11.6 +11.7 +11.8
unit dummies (fe) +26.4 +10.7 +5.3 +2.5
random intercept (re) +20.6 +10.8 +5.8 +2.9
Mundlak +0.3 -0.1 +0.2 -0.0

The pooled and random-intercept estimators are biased by the omitted correlated effect (the pooled bias has a closed form under this design, +11.8 percent); the dummies carry the incidental-parameters bias that fades with T; the Mundlak device is essentially unbiased at every T. Hence the recommendation: mundlak() (with cluster = or re =) for short panels, fe = – with the jackknife if the half-panels identify the parameters – for long ones.

References

Dale, D. and Sirchenko, A. (2021). Estimation of nested and zero-inflated ordered probit models. Stata Journal, 21, 3-38.

Dhaene, G. and Jochmans, K. (2015). Split-panel jackknife estimation of fixed-effect models. Review of Economic Studies, 82, 991-1030.

Greene, W. (2004). The behaviour of the maximum likelihood estimator of limited dependent variable models in the presence of fixed effects. Econometrics Journal, 7, 98-119.

Mundlak, Y. (1978). On the pooling of time series and cross section data. Econometrica, 46, 69-85.

Wooldridge, J.M. (2010). Econometric Analysis of Cross Section and Panel Data, 2nd ed. MIT Press.