*! version 1.0.0 02feb2024 Maximilian Sprengholz & Maik Hamjediers

Title

nopo -- Matching-based decomposition analysis of differences in outcomes between two groups following Ñopo (2008)

Dependencies

Requires kmatch (Jann, 2017) to be installed, which has
moremata as dependency.

Syntax

nopo decomp depvar varlist [if] [in] [weight] , by(varname) [options]

As postestimation to a matching via kmatch:

nopo decomp [, kmpassthru(string) kmkeepgen]

General
by(varname) Group variable by which to estimate and decompose gaps in (required)

swap Swap groups

xref(varname == #) Set reference group in terms of characteristics

bref(varname == #) Set reference group in terms of returns

Matching procedure
kmatch(em|md|ps) Choose between exact (em, default), multivariate-distance (md), and propensity score (ps) matching

kmopts(string) Matching-specific options according to kmatch

Reporting
normalize Normalize estimates by mean outcome of group A

kmnoisily Display output from internal kmatch call

kmpassthru(string) Adds results of interal kmatch to the stored results of nopo decomp

kmkeepgen Keep matching and weight variables generated by kmatch

fweights, pweights, and iweights are allowed.

Allows for the bootstrap and jackknife prefix for standard errors.

See nopo postestimation for three available features after estimation (nopo summarize, nopo gapoverdist, nopo dadb).

Description

nopo decomp provides a Ñopo-style (2008) decomposition of the gap D in the average outcome Y
between two groups A and B by matching them on a set of characteristics X predictive of Y.

D = YB - YA

= D0 + DX + DA + DB , where

- D0 is the part of the gap not attributable to compositional differences between A and B in X among matched units (classic unexplained component)

- DX is the part of the gap attributable to compositional differences between A and B in X among matched units (classic explained component)

- DA is the part of the gap attributable to unmatched units in A

- DB is the part of the gap attributable to unmatched units in B

For this decomposition, the matching generates counterfactual group A^B by weighting all matched observations of group A in order to provide the exact same distribution in X as matched units of group B. The outcome of this counterfactual group can be interpreted in two ways: (1) as the average outcome of group A if it had the same characteristics as group B (for which we denote group B as xref) and (2) as the average outcome of group B if it had the same returns to characteristics as group A (for which we denote group A as bref). One can easily change this interpretation, by switching the matching direction and producing the counterfactual group B^A using the xref() or bref() option.

Note that positive values for DA reflect unmatched units having lower values in Y than matched units among group A, whereas positive values of DB reflect unmatched units having higher values in Y than matched units among group B.

A detailed explanation of the methodology is provided in an online documentation.

Matching approaches:

Ñopo's original proposition used exact matching but extends to other matching approaches,
two of which are additionally available in nopo decomp: multivariate-distance and propensity-score matching.

An exact matching ensures that the interpretation of the unexplained D0 and explained DX components
directly refer to the characteristics X (e.g., D0 being the remaining gap if both groups had the same
characteristics as group B).
This interpretation changes slightly in the case of multivariate-distance and propensity-score matching, as D0
then refers to both groups having an equal likelihood to be the group specified as xref based on the characteristics X.
Note that the results of the decomposition may hinge on the specifics of either matching procedure
(e.g., the extent of coarsening of continuous variables before exact matching, or the bandwidth selection
for determining matches in terms of the propensity-score or multivariate-distance).

To implement each matching procedure, nopo decomp either internally calls kmatch or it can be used
as a postestimation to a previous matching via kmatch. While kmatch provides average treatment
effects on the treated (ATT) or controls (ATC) that are equal to the unexplained component D0, nopo decomp
additionally estimates the other three decomposition-components DX, DA, and DB.

Standard errors:

Please use the bootstrap or jackknife prefix to obtain standard errors (see Examples).
We are working out how the analytical SEs as detailed by Ñopo (2008) for D0
(and implemented in nopomatch) extend to the full set of components in the
presence of covariance. If you can help, please reach out to us via
GitHub.

Postestimation:

See nopo postestimation for available features after estimation.

Options

General

by(varname) specifies the groups between which we estimate and
decompose the gap in (required). Needs to be numeric with two levels. By default, the gap is
definied as the mean value of the first by group is substracted from the second group, and
the first group is matched to the second group via a one-to-many matching.
Use xref()/bref() to adjust the matching direction or swap to change.

swap groups A and B, so that the sign of D is reversed and and the respective reference
for characteristics and returns is switched.

xref(varname == #) allows to adjust the matching direction and thereby
manually set the reference group for the counteractual group in terms of characteristics.
Naturally, xref() and bref() cannot be the same.

bref(varname == #) allows to adjust the matching direction and thereby
manually set the reference group for the counteractual group in terms of returns.
Naturally, bref() and xref() cannot be the same.

Matching procedure

kmatch(em|md|ps) lets you choose the measure how both groups are matched, while the
decomposition always relays on a one-to-many matching procedure. The default is to use
exact matching kmatch(em), in which case all variables in varlist are treated as
factors. For multivariate-distance kmatch(md) and propensity score kmatch(ps)
matching, make sure to indicate via factor notation which variables are factors and which are
continuous (everything is passed through to the internal kmatch call as is). To further tweak the
matching, you can use kmopts() or, for maximum flexibility, call nopo decomp after a
manual kmatch call with all the necessary options.

kmopts(string) are options passed on to kmatch when
called internally. See general_options,
matching_options and the matching-type specific options
em_options,
md_options, or ps_options.

Reporting

normalize estimates by the depvar mean of group A. Coefficients can then be interpreted in a
relative manner, e.g. that group B earns on average x percent wages relative to group A.
The comparison group can be changed by using the option swap.
Generates _depvar_norm.

kmnoisily Show output of internal kmatch call.

kmpassthru(string) lets you pass through further
kmatch stored results to the stored results of nopo decomp.
For example: kmpassthru(df_r metric) would add residual degrees of freedom and
type of multivariate distance metric as stored macros to the sored results of nopo decomp.

kmkeepgen keeps the matching and weight variables generated by kmatch,
which are dropped by default. In the standalone call, these variables are prefixed by _KM_).
Note that some of the kmatch variables contain the same information as the variables returned by
nopo decomp (prefixed by _nopo_).

Examples

Example data (click to run)

. use http://fmwww.bc.edu/RePEc/bocode/o/oaxaca.dta , clear

. for any exper tenure: gen X_c = round(X,5)

. gen educ_c = round(educ,1)

. lab var educ_c "years of educational attainment (rounded)"

. lab var exper_c "years of work experience (5-year intervalls)"

. lab var tenure_c "years of job tenure (5-year intervalls)"

. lab def female 0 "Men" 1 "Women"

. lab val female female

Decomposition - Standalone

. nopo decomp lnwage educ_c exper_c tenure_c, by(female)

Decomposition - After kmatch

. kmatch em female educ_c exper_c tenure_c (lnwage), att

. nopo decomp

Decomposition - Using propensity-score or multivariate-distance matching

. nopo decomp lnwage educ_c exper_c tenure_c, by(female) kmatch(ps)

. nopo decomp lnwage educ_c exper_c tenure_c, by(female) kmatch(md)

Standard errors

. bootstrap, reps(100): nopo decomp lnwage educ_c exper_c tenure_c, by(female)

Obtain the same results as nopomatch

. nopomatch educ_c exper_c tenure_c, outcome(lnwage) by(female)

. nopo decomp lnwage educ_c exper_c tenure_c, by(female) xref(0) normalize

Comparison to twofold regression-based decomposition via oaxaca

. oaxaca lnwage educ exper tenure, by(female) weight(0) nodetail

. nopo decomp lnwage educ_c exper_c tenure_c, by(female) swap

Stored results

nopo decomp stores the following in e():

Scalars

e(nstrata) number of strata (or undefined)

e(nstrata_matched) number of matched strata (or undefined)

e(nn) number of requested neighbors (or undefined)

e(N) number of observations

e(nA) number of observations of group A

e(mshareA) percentage of matched units among group A

e(msharewA) weighted percentage of matched units among group A

e(mgapA) mean difference in depvar between matched and unmatched units of group A

e(nB) number of observations of group B

e(mshareB) percentage of matched units among group B

e(msharewB) weighted percentage of matched units among group B

e(mgapB) mean difference in depvar between matched and unmatched units of group B

Macros

e(kmatch_cmdline) command line of interal kmatch call

e(kmatch_subcmd) type of matching (md, ps, or em

e(strata) name of variable that denotes matching stratum

e(mweight) name of variable that denotes matching weight

e(matched) name of variable that denotes matching indicator

e(matchset) list of variables on which groups are matched

e(groupA) expression that defines group A in terms of group-variable

e(groupB) expression that defines group B in terms of group-variable

e(xref) expression for the reference group in terms of characteristics

e(bref) expression for the reference group in terms of returns

e(cval) list of variables on which groups are matched

e(tval) list of variables on which groups are matched

e(tvar) name of group variable

e(teffect) matching direction (ATT or ATC)

e(wexp) weight expression (if weights are applied)

e(wtype) fweights, pweights, and iweights (if weights are applied)

e(cmd) nopo

e(properties) b

Matrices

e(b) vectors of all gap-estimates

Functions

e(sample) marks estimation sample

Additional to the above, the following is stored in r():

Matrices

r(table) matrix of the descriptive matching block (upper table in output)

nopo decomp generates the following variables:

_nopo_matched Matching indicator (dummy)

_nopo_mweight Matching weight

_nopo_strata Matching stratum (kmatch(em) only)

_nopo_ps Matching propensity score (kmatch(ps) only)

_depvar_norm Normalized depvar (if normalize was specified)

Any results from the internal kmatch call can be added to e() via the kmpassthru() option.

If bootstrap- or jackknife-prefix is used, additional results as described in help
bootstrap and jackknife are stored in e().

References

Jann, B. (2017). kmatch: Stata module for multivariate-distance and propensity-score matching,
including entropy balancing, inverse probability weighting, (coarsened) exact matching, and
regression adjustment. Available from //ideas.repec.org/c/boc/bocode/s458346.html.

Ñopo, H. (2008). Matching as a Tool to Decompose Wage Gaps. The Review of Economics
and Statistics, 90(2), 290–299. https://doi.org/10/b6tqwq

Acknowledgements

Special thanks to Carla Rowold for stress testing and many helpful comments.

Authors

Maximilian Sprengholz, maximilian.sprengholz@hu-berlin.de

Maik Hamjediers, maik.hamjediers@hu-berlin.de

Department of Social Sciences,

Humboldt-Universität zu Berlin