Asymmetric Poisson Pseudo-Maximum Likelihood (APPML)

library(capybara)
#> Registered S3 method overwritten by 'capybara':
#>   method         from
#>   update.formula stats

Overview

Standard Poisson Pseudo-Maximum Likelihood (PPML) estimates the conditional mean of the outcome variable. fepoisson_asymmetric() extends this by fitting conditional expectiles β€” a generalization that lets you examine different parts of the conditional distribution with the same efficiency gains of high-dimensional fixed effects.

The implementation follows Bergstrand et al.Β (2025): instead of minimizing a symmetric loss, the estimator minimizes an asymmetric weighted loss controlled by a single parameter expectile (\(\tau \in (0, 1)\)):

  • \(\tau = 0.5\) β€” standard PPML (symmetric, estimates the conditional mean).
  • \(\tau < 0.5\) β€” places more weight on observations with negative residuals, pulling estimates toward the lower part of the distribution.
  • \(\tau > 0.5\) β€” places more weight on observations with positive residuals, shifting estimates toward the upper part of the distribution.

The expectile is set through fit_control() and defaults to 0.5, so if you don’t specify it, fepoisson_asymmetric() will behave like standard PPML.

Estimating lower and upper expectiles

Shifting expectile away from 0.5 lets you trace how the entire conditional distribution of mpg varies with wt, after absorbing the cyl fixed effects.

# 10th expectile β€” sensitive to small values of mpg
mod_low <- fepoisson_asymmetric(
  mpg ~ wt | cyl,
  data    = mtcars,
  control = fit_control(expectile = 0.1)
)
# Standard PPML: expectile = 0.5 recovers the conditional mean
mod_ppml <- fepoisson_asymmetric(
  mpg ~ wt | cyl,
  data    = mtcars,
  control = fit_control(expectile = 0.5)
)
summary(mod_ppml)
#> Formula: mpg ~ wt | cyl
#> <environment: 0x5641bac33f88>
#>
#> Family: Poisson
#>
#> Estimates:
#>
#> |    | Estimate | Std. Error | z value | Pr(>|z|) |
#> |----|----------|------------|---------|----------|
#> | wt |  -0.1799 |     0.0716 | -2.5126 | 0.0120 * |
#>
#> Significance codes: ** p < 0.01; * p < 0.05; + p < 0.10
#>
#> Fixed effects:
#>   cyl: 3
#>
#> Number of observations: Full 32; Missing 0; Perfect classification 0
#>
#> Number of Fisher Scoring iterations: 4
# 90th expectile β€” sensitive to large values of mpg
mod_high <- fepoisson_asymmetric(
  mpg ~ wt | cyl,
  data    = mtcars,
  control = fit_control(expectile = 0.9)
)

Comparing coefficients across expectiles

A natural use-case is comparing how the effect of a regressor changes across the distribution. The table below collects the coefficient on wt at the three expectile levels:

summary_table(
  mod_low, mod_ppml, mod_high,
  model_names = c("10th expectile", "PPML (50th expectile)", "90th expectile")
)
#> |     Variable     |  10th expectile  | PPML (50th expectile) |  90th expectile  |
#> |------------------|------------------|-------------------|------------------|
#> | wt               |           -0.197 |           -0.180* |           -0.160 |
#> |                  |          (0.141) |           (0.072) |          (0.142) |
#> |                  |                  |                   |                  |
#> | Fixed effects    |                  |                   |                  |
#> | cyl              |              Yes |               Yes |              Yes |
#> |                  |                  |                   |                  |
#> | N                |               32 |                32 |               32 |
#>
#> Standard errors in parenthesis
#> Significance levels: ** p < 0.01; * p < 0.05; + p < 0.10

A negative coefficient that grows in magnitude from low to high would indicate that heavier cars are disproportionately associated with low mpg at the top of the distribution β€” a pattern that standard PPML would average out.

Convergence diagnostics

The outer APPML loop updates observation weights until the coefficient vector stops changing. You can inspect convergence through the returned list elements:

cat("Outer loop converged:", mod_ppml$conv_outer, "\n")
#> Outer loop converged: TRUE
cat("Outer iterations:    ", mod_ppml$iter_outer, "\n")
#> Outer iterations:     1
cat("Expectile used:      ", mod_ppml$expectile,  "\n")
#> Expectile used:       0.5

References

Bergstrand, Jeffrey H., Matthew W. Clance, and JMC Santos Silva. β€œThe tails of gravity: Using expectiles to quantify the trade-margins effects of economic integration agreements.” Journal of International Economics (2025): 104145.

Loading...