
Oaxaca-Blinder decomposition of a sentencing gap, with its two references and the interaction
Source:R/disparity_decomposition.R
morie_disparity_decomposition.RdFits formula separately in the two groups by least squares (so each
fitted line passes through its group means, Research.P15.Groups.yA_eq)
and decomposes the gap in mean outcomes exactly, three ways: explained at
group B's coefficients plus unexplained at A's means (twofold_B), the
same with the roles swapped (twofold_A), and endowments plus
coefficients plus interaction (threefold). The two explained parts
differ by exactly the interaction (reference_dependence), so the
share of a gap "explained by legal factors" is a choice of reference. The
per-variable attribution of the unexplained part moves when a covariate is
re-centred (attribution_shift); the function reports that shift for
each covariate so a reader sees how far the lines can move.
Arguments
- formula
Outcome on covariates, e.g.
sentence ~ offence_score + priors.- data
Data frame.
- group
Name of the two-level grouping variable (character or factor).
- reference
Level treated as group B (the "reference prices"); the other is A.
- shift
Recentring amount used to report the attribution shift per covariate.
Value
A list with levels, means (outcome means), gap,
twofold_B, twofold_A (each with explained,
unexplained), threefold (endowments,
coefficients, interaction), by_variable (a data frame
with each covariate's explained and unexplained contributions under the
B reference, and unexplained_shift = shift * (beta_A - beta_B)),
identity_checks and theorems.
Examples
set.seed(3)
n <- 400
g <- rep(c("A", "B"), each = n / 2)
score <- rnorm(n, ifelse(g == "A", 5, 4)); priors <- rpois(n, ifelse(g == "A", 2, 1))
sentence <- 2 + 0.8 * score + 0.5 * priors + ifelse(g == "A", 1, 0) + rnorm(n)
d <- data.frame(sentence, score, priors, g)
r <- morie_disparity_decomposition(sentence ~ score + priors, d, group = "g", reference = "B")
c(gap = r$gap, explained_B = r$twofold_B[["explained"]], interaction = r$threefold[["interaction"]])
#> gap explained_B interaction
#> 2.23260343 1.40297787 0.02920949