11 PPML
11.1 Purpose
This chapter explains zero-inclusive and multiplicative gravity estimators for the Post-Soviet replication. It covers PPML, GPML, NBPML, and structural PPML with exporter-year and importer-year fixed effects.
11.2 Theory
Modern gravity models are multiplicative. Estimating a log-linear model with OLS changes the model and drops zero trade flows. PML estimators keep flow in levels and specify a conditional mean.
The general conditional-mean form is:
\[ \begin{aligned} E[flow_{ijt} \mid X_{ijt}] &= \exp(X_{ijt}\beta) \end{aligned} \]
where \(X_{ijt}\) includes log(distw), comlang_off, contig, wto_joint, EU_joint, EAEU_joint, year, and fixed effects when required.
11.3 Why PML estimators exist
PML estimators exist because trade data are skewed, heteroskedastic, and often include zero flows. They allow students to estimate gravity models without transforming the dependent variable into log(flow).
11.5 PPML
11.5.1 Theory
PPML estimates the exponential conditional mean of trade in levels. It is widely used in gravity because it can keep valid zero trade flows and is robust to important heteroskedasticity concerns.
11.5.2 Equation
\[ \begin{aligned} E[flow_{ijt} \mid X_{ijt}] &= \exp\left( \beta_0 + \beta_1 \log(gdp\_o_{it}) + \beta_2 \log(gdp\_d_{jt}) \right.\\ &\quad \left. + \beta_3 \log(distw_{ij}) + \gamma Z_{ijt} + \delta_t \right) \end{aligned} \]
11.5.3 Advantages
- Keeps
flow == 0when zeros are valid observations. - Estimates the multiplicative gravity model directly.
- Coefficients can be interpreted through semi-elasticities.
- Works naturally with fixed effects in structural gravity.
11.5.4 Limitations
- Can be computationally heavy with many fixed effects.
- Sensitive to separation and convergence issues.
- Requires careful checking of zeros and missing values.
- Standard
statsmodelsdummy expansion may not scale to very large panels.
11.5.5 R implementation
library(fixest)
df <- read.csv("data/gravity_clean.csv")
ppml_r <- fepois(
flow ~ log(distw) + comlang_off + contig +
wto_joint + EU_joint + EAEU_joint |
year,
data = df,
vcov = "hetero"
)
summary(ppml_r)11.5.6 Python implementation
ppml_formula = (
"flow ~ log_gdp_o + log_gdp_d + log_distw + "
"comlang_off + contig + wto_joint + EU_joint + EAEU_joint + C(year)"
)
ppml_py = smf.glm(
formula=ppml_formula,
data=df,
family=sm.families.Poisson(),
).fit(cov_type="HC1")11.5.7 Interpretation
For continuous logged variables, coefficients are elasticity-like. For dummy variables:
\[ 100 \times \left(\exp(\gamma) - 1\right) \]
is the conditional percent difference associated with the dummy.
11.6 GPML
11.6.1 Theory
Gamma PML estimates a positive continuous dependent variable with a log link. It is sometimes used as an alternative multiplicative estimator when the dependent variable is strictly positive.
11.6.2 Equation
\[ \begin{aligned} E[flow_{ijt} \mid X_{ijt}] &= \exp(X_{ijt}\beta), \quad flow_{ijt} > 0 \end{aligned} \]
11.6.3 Why it exists
GPML exists as an alternative quasi-likelihood for positive continuous outcomes. In gravity work, it can be compared with PPML when the sample excludes zero flows.
11.6.4 Advantages
- Models positive continuous trade values in levels.
- Uses a log link, preserving multiplicative interpretation.
- Useful as a robustness comparison.
11.6.5 Limitations
- Cannot use zero trade flows directly.
- Not the default modern gravity estimator.
- Results can differ from PPML because the variance assumption differs.
11.6.6 R implementation
gpml_df <- subset(df, flow > 0)
gpml_r <- glm(
flow ~ log(gdp_o) + log(gdp_d) + log(distw) +
comlang_off + contig + wto_joint + EU_joint + EAEU_joint +
factor(year),
data = gpml_df,
family = Gamma(link = "log")
)11.6.7 Python implementation
gpml_df = df.loc[df["flow"] > 0].copy()
gpml_formula = (
"flow ~ log_gdp_o + log_gdp_d + log_distw + "
"comlang_off + contig + wto_joint + EU_joint + EAEU_joint + C(year)"
)
gpml_py = smf.glm(
formula=gpml_formula,
data=gpml_df,
family=sm.families.Gamma(link=sm.families.links.Log()),
).fit(cov_type="HC1")11.6.8 Interpretation
Interpret dummy and continuous coefficients using the same exponential logic as PPML, but state that GPML uses a positive-flow sample.
11.7 NBPML
11.7.1 Theory
Negative binomial PML is another multiplicative estimator. It allows overdispersion relative to Poisson. In trade applications, it can be used as a robustness estimator when variance appears much larger than the mean.
11.7.2 Equation
\[ \begin{aligned} E[flow_{ijt} \mid X_{ijt}] &= \exp(X_{ijt}\beta) \end{aligned} \]
with a negative-binomial variance structure.
11.7.3 Why it exists
NBPML exists to relax the strict Poisson variance relationship while retaining a log-link conditional mean.
11.7.4 Advantages
- Allows overdispersion.
- Keeps level-based interpretation.
- Can include zero flows.
- Useful as a robustness comparison.
11.7.5 Limitations
- Can be harder to estimate and interpret.
- May be sensitive to convergence and dispersion assumptions.
- Not a substitute for thinking carefully about zeros, fixed effects, and model design.
11.7.6 R implementation
library(MASS)
nbpml_r <- glm.nb(
flow ~ log(gdp_o) + log(gdp_d) + log(distw) +
comlang_off + contig + wto_joint + EU_joint + EAEU_joint +
factor(year),
data = df
)11.7.7 Python implementation
nbpml_formula = (
"flow ~ log_gdp_o + log_gdp_d + log_distw + "
"comlang_off + contig + wto_joint + EU_joint + EAEU_joint + C(year)"
)
nbpml_py = smf.glm(
formula=nbpml_formula,
data=df,
family=sm.families.NegativeBinomial(),
).fit(cov_type="HC1")11.7.8 Interpretation
Interpret coefficients through the exponential conditional mean. Report NBPML as a robustness estimator unless the research design gives a specific reason to prefer it.
11.8 Zero-inclusive PPML
11.8.1 Theory
Zero-inclusive PPML keeps observations where flow == 0 as long as they are true observed zero trade flows rather than missing or miscoded values.
11.8.2 Equation
\[ \begin{aligned} E[flow_{ijt} \mid X_{ijt}] &= \exp(X_{ijt}\beta), \quad flow_{ijt} \ge 0 \end{aligned} \]
11.8.3 Why it exists
Zero-inclusive PPML exists because zero trade flows are economically meaningful in many gravity panels. Dropping them can change the research question.
11.8.4 R implementation
zero_ppml_r <- fepois(
flow ~ log(distw) + comlang_off + contig +
wto_joint + EU_joint + EAEU_joint |
year,
data = df,
vcov = "hetero"
)11.8.5 Python implementation
zero_ppml_df = df.loc[df["flow"] >= 0].copy()
zero_ppml_py = smf.glm(
formula=ppml_formula,
data=zero_ppml_df,
family=sm.families.Poisson(),
).fit(cov_type="HC1")11.8.6 Interpretation
State clearly whether zeros are included and how many observations enter the model. The key comparison is not only coefficient size but also sample definition.
11.9 Structural PPML with exporter-year and importer-year fixed effects
11.9.1 Theory
Structural PPML absorbs exporter-year and importer-year conditions. This is close to modern structural gravity practice because it controls for time-varying exporter supply, importer demand, and multilateral resistance.
11.9.2 Equation
\[ \begin{aligned} E[flow_{ijt} \mid X_{ijt}] &= \exp\left( \gamma_1 wto\_joint_{ijt} + \gamma_2 EU\_joint_{ijt} + \gamma_3 EAEU\_joint_{ijt} \right.\\ &\quad \left. + \mu_{ij} + \alpha_{it} + \delta_{jt} \right) \end{aligned} \]
where \(\mu_{ij}\) is a pair fixed effect, \(\alpha_{it}\) is an exporter-year fixed effect, and \(\delta_{jt}\) is an importer-year fixed effect.
11.9.3 Why it exists
This model exists to compare institutional changes within pairs while absorbing time-varying exporter and importer conditions.
11.9.4 Advantages
- Closely connected to structural gravity.
- Keeps zero flows through PPML.
- Controls for rich exporter-year and importer-year heterogeneity.
- Focuses interpretation on institutional variables that vary over time.
11.9.5 Limitations
- Requires exporter and importer identifiers.
- Absorbs
gdp_o,gdp_d, and many country-year variables. - Can be computationally expensive in ordinary Python dummy expansion.
- May require specialized estimators for large panels.
11.9.6 R implementation
df$pair_id <- paste(df$iso3_o, df$iso3_d, sep = "_")
structural_ppml_r <- fepois(
flow ~ wto_joint + EU_joint + EAEU_joint |
pair_id + iso3_o^year + iso3_d^year,
data = df,
vcov = "hetero"
)11.9.7 Python implementation
The transparent statsmodels version is useful for teaching but may be slow.
df["pair_id"] = df["iso3_o"] + "_" + df["iso3_d"]
structural_ppml_formula = (
"flow ~ wto_joint + EU_joint + EAEU_joint + "
"C(pair_id) + C(iso3_o):C(year) + C(iso3_d):C(year)"
)
structural_ppml_py = smf.glm(
formula=structural_ppml_formula,
data=df,
family=sm.families.Poisson(),
).fit(cov_type="HC1")11.9.8 Interpretation
In this saturated model, the institutional coefficients are identified from within-pair changes after controlling for exporter-year and importer-year shocks. Do not interpret gdp_o, gdp_d, or distw in this model, because they are absorbed or excluded by design.
11.10 Estimator comparison table
Students should create a comparison table with no invented results:
| Estimator | Dependent variable | Zero flows | Key institutional variables | Main caution |
|---|---|---|---|---|
| OLS | log(flow) |
Dropped | wto_joint, EU_joint, EAEU_joint |
Positive-flow sample only |
| PPML | flow |
Included if valid | wto_joint, EU_joint, EAEU_joint |
Check convergence and separation |
| GPML | flow |
Dropped | wto_joint, EU_joint, EAEU_joint |
Positive-flow sample only |
| NBPML | flow |
Included if valid | wto_joint, EU_joint, EAEU_joint |
Dispersion assumptions |
| Structural PPML | flow |
Included if valid | wto_joint, EU_joint, EAEU_joint |
High-dimensional fixed effects |
11.11 Research output
Prepare a PML replication plan that specifies which observations enter PPML, GPML, NBPML, and structural PPML; which fixed effects are included; and how institutional coefficients will be interpreted.