Differences between implementations¶
dpd-stream follows Stata’s xtabond2 where conventions differ (xtabond2 3.7.2). This page lists the differences we found when comparing it with other implementations, at the versions below, so that a difference in someone’s output can be traced. “Differs” is not “wrong”: most are different conventions for the same model, and where one is a limitation or a likely bug, we say so.
Implementation |
Version |
Compared on |
|---|---|---|
xtabond2 |
3.7.2 |
about fifty specifications; the reference |
xtdpdgmm |
nonlinear moments, system GMM, forward orthogonal deviations |
|
ivreg2 / |
identification tests |
|
pydynpd |
0.2.2 |
difference and system GMM |
plm |
2.6.7 |
difference and system GMM, Windmeijer, AR tests |
pdynmc |
0.9.13 |
difference and system GMM, nonlinear moments |
systemgmmkit |
1.0.5 |
collapsed difference and system GMM |
Where they agree¶
xtabond2 agrees with dpd-stream to 1e-5 or better in coefficients, standard errors and every test, on the specifications that both run.
pydynpd agrees to rounding in difference and system GMM, collapsed or not.
plm and pdynmc agree to rounding in difference GMM (plm’s Windmeijer errors and AR tests too, on the Arellano–Bond data).
systemgmmkit agrees to rounding in first-differenced difference GMM, and in system GMM once its conventions below are matched, on balanced panels and on unbalanced ones without gaps.
Conventions that change the estimates¶
Which equation an IV-style instrument serves. In system GMM, xtabond2
(and dpd-stream by default) uses an IV-style instrument such as the exogenous
\(w\) in both equations: \(E[\Delta w_{it}\,\Delta\varepsilon_{it}] = 0\) and
\(E[w_{it}(\alpha_i + \varepsilon_{it})] = 0\). systemgmmkit uses it in the levels
equation only (iv(w, eq='level') is the same model here). xtdpdgmm’s
iv(w) in a differenced equation uses \(w\) itself, not \(\Delta w\) (iv(w, difference) is xtabond2’s). dpd-stream takes iv(w, passthru=True) for
xtdpdgmm’s.
Time effects in the levels equation. In system GMM, dpd-stream’s year
effects are xtabond2’s: a dummy per year, each an IV-style instrument for both
equations (iv(yr*)), checked against xtabond2 at 1e-5 or better (Arellano
and Bond’s data, and a simulated panel with | year). pydynpd’s timedumm
agrees with it to rounding. plm and pdynmc give system-GMM estimates 0.1 to
0.14 from ours on the benchmark panel, which we attribute to how they enter the
year effects in the levels equation, though we did not trace it. systemgmmkit
with time effects also differs, from placing the dummies’ instruments
differently. Difference GMM agrees in all of them.
Lags by period or by row. xtabond2 and dpd-stream take lags by the value of the time variable, so a gap makes the lag missing. systemgmmkit takes them by position in the panel, so across a gap it has more observations (752 against 734 in one test panel) and different estimates. The two agree on unbalanced panels without gaps.
Forward orthogonal deviations. The deviation is \(\varepsilon^*_{it} = c_t(\varepsilon_{it} - \bar\varepsilon_{i,t+1:T})\). With \(c_t^2 = (T-t)/(T-t+1)\) the transformed errors have equal variances, which is xtabond2’s choice and dpd-stream’s. xtdpdgmm uses \(c_t^2\) in place of \(c_t\), so it weights the rows differently, and the estimates differ whenever instruments are shared across periods (collapsed ones, IV-style ones; with one instrument per period the scale cancels). We reproduced xtdpdgmm’s fit to six digits only with that scale. systemgmmkit’s orthogonal-deviation fits have different instrument sets (12 against 14 in one difference-GMM test) and different estimates, and its Arellano–Bond AR(1) statistic is near zero where the others’ is large and negative.
Ahn–Schmidt moments. dpd-stream and xtdpdgmm agree to six digits, in
difference and system GMM, balanced or not, once the first-step weights match
(the nonlinear block’s weight is \(1/N_g\) times nl_weight, and nl(iid)’s
added linear moments sit in the \(Z'HZ\) block). pdynmc defines the same
moments but needs a third difference, so its set is one moment shorter; its
one-step fit matches ours with that moment dropped. Its two-step estimate
differs from ours by up to 0.6 standard errors; it is the minimizer of its
own objective, and we did not resolve why that objective differs.
Collapsed levels instruments. xtabond2 searches for a collapsed levels-instrument column that is empty and moves it to deeper lags, across panel boundaries; dpd-stream does it within each panel.
Conventions that change only standard errors and statistics¶
Small-sample factor. systemgmmkit multiplies its variance by xtabond2’s
small factor, \(\frac{G}{G-1}\cdot\frac{N-1}{N-K}\); dpd-stream’s
small=True gives the same standard errors.
Nonlinear-fit standard errors. xtdpdgmm’s reported variance for Ahn–Schmidt fits differs by up to 3% (balanced two-step; more unbalanced) from the exact one for its own moments. Its stored weight matrix and Hansen statistic equal ours, and our Jacobian satisfies the first-order condition at its estimates, so we keep ours.
Statistics that xtabond2 changed after Roodman (2009). The Sargan statistic’s \(\hat\sigma^2\) divides by the differenced equation’s observations (not the levels’), and the model test includes the constant. dpd-stream follows 3.7.2; the article’s two numbers differ for that reason.
Defaults. The default estimator differs: xtabond2 and xtdpdgmm are one-step, pydynpd two-step with Windmeijer’s correction, pdynmc iterated. dpd-stream is two-step Windmeijer. MMSC counts the constant in \(k\) in dpd-stream; pydynpd’s omits it while its Hansen degrees of freedom count it.
Identification tests. After xtabond2, Stata’s underid computes
Kleibergen–Paap by ranktest’s nosvd form (a J statistic at LIML
estimates) and Sanderson–Windmeijer by a two-step GMM with a \(Z'HZ\) first
step. dpd-stream computes ivreg2’s forms: Kleibergen–Paap by the SVD algebra
and Sanderson–Windmeijer by 2SLS. They are asymptotically equivalent under the
null and differ by a few percent in finite samples
(identification).
What each implementation offers¶
xtabond2 is the reference for options (
h(),split,passthru,mz,pca) and the tests. It holds each panel’s instrument matrix in memory.xtdpdgmm has more specialized options than dpd-stream. dpd-stream matches its
nl(), but not its rescaling in unbalanced panels.pydynpd is a port of xtabond2’s commands to Python: difference and system GMM, collapsed or not, two-step with Windmeijer’s correction.
plm
pgmmhas difference and system GMM with Windmeijer’s correction and the AR tests.pdynmc adds Ahn–Schmidt moments and iterated GMM, and is the slowest at scale.
systemgmmkit builds collapsed instruments only (
collapse=Falseis ignored), clusters by panel only, takes no weights, and has no nonlinear moments, absorbed effects or identification tests. At a million panels it refuses the time variable as an “unsafe unit-spaced grid” and asks for a contiguous period index.dpd-stream has none of: continuously-updating GMM, several absorbed fixed effects at once, GPUs, or xtdpdgmm’s more specialized options.
For speed and memory at scale, see the benchmarks.
benchmarks/external/ has the scripts behind the numerical comparisons.
Comparing output¶
To compare dpd-stream with another implementation, match the model first: the
same equation for each instrument (above), the same lag limits (xtdpdgmm’s
lag(1 3) is lags 1 to 3 of the variable, as xtabond2’s), the same
transformation and scale, the same sample (gaps), and the same variance
(small, one- or two-step). A one-step fit with an identity weight depends
on the moments alone, which separates a difference in the moments from a
difference in the weighting.