help mata mm_ebalance()

Title

mm_ebalance() -- Entropy balancing

Syntax

Initialize a new mm_ebalance() object

class mm_ebalance scalar S
or
S = mm_ebalance()

Settings

S.tau(tau) target sum of balancing weights; tau
can be a (strictly positive) real number or, alternatively, "Wref"
(sum of weights in reference sample), "W" (sum of weight in main
sample), "Nref" (number of rows in Xref), or "N" (number of
rows in X); default is "Wref"

S.scale(scale) scales to be used for standardization;
scale can be a (strictly positive) real vector providing custom values
(same length as columns in X) or, alternatively,
"main" (standard deviations from main sample), "ref"
(standard deviations from reference sample), "avg"
(average between main and ref), "wavg" (weighted average
between main and ref), or pooled (standard deviations from
pooled sample); standard deviations are computed using population formulas (division
by N rather than N-1); scales equal to 0 will be reset to 1; default is "main"

S.[no]adj(p) selects the means to be
adjusted where p is a vector of indices referring to columns of X;
S.adj(p) causes all selected means to be adjusted and
all non-selected means to be held fixed; alternatively,
S.noadj(p) causes all selected means to be held fixed
and all non-selected means to be adjusted; the elements in p must be
>= 1; duplicates and elements pointing to columns that do not exist
will be ignored; specify S.adj(.) to adjust all means (the default)

S.btol(btol) balancing tolerance; default is 1e-6;
balancing is achieved if the balancing loss is smaller than btol

S.ltype(ltype) type of balancing loss function, can be "reldif"
(maximum relative difference; the default), "absdif"
(maximum absolute difference), or "norm" (Euclidean norm of differences)

S.etype(etype) evaluator type, can be "bl"
(evaluator based on balancing loss; the default), "wl"
(evaluator based on distribution of weights), "mm" (method of moments
evaluator), or "mma" (method of moments evaluator including intercept);
when using an evaluator other than "bl" you might want to reduce
vtol a bit (e.g. to 1e-10)

S.trace(trace) trace level; default is "value";
specify "none" to suppress iteration log; see
optimize() for details

S.maxiter(maxiter) maximum number of iterations;
default is as set by set maxiter

S.ptol(ptol) convergence tolerance for coefficient
vector; default is 1e-6; convergence is reached if ptol or vtol is
satisfied; also see optimize()

S.vtol(vtol) convergence tolerance for the minimization
criterion; default is 1e-7; convergence is reached if ptol or vtol is
satisfied; also see optimize()

S.difficult(diff) stepping
algorithm to be used in nonconcave regions; diff=0 (the default) uses
the standard algorithm; diff!=0 uses an alternative algorithm; see the
singular H methods in optimize() and
the description of the difficult option in maximize

S.nostd(nostd) whether standardization should be applied
during optimization to improve robustness of the algorithm; nostd=0 (the default)
fits the coefficients using standardized data and then back-transforms the
results; nostd=1 omits such standardization (not recommended); in any case,
the balancing loss of the final fit will be obtained from the original data

S.nowarn(nowarn) whether "convergence not achieved"
and "balance not achieved" messages should be displayed; nowarn=0 (the default)
displays the messages; nowarn!=0 suppresses the messages

Settings can be changed at any time, but changing a setting will clear
any results that may already exist in S (but not the data).

All functions for settings can be used without argument to retrieve a setting. For
example, type ltype = S.ltype() to retrieve the setting for the
type of loss function. The functions do not clear results if used in this form.

Provide data

S.data(X, w, Xref, wref [, fast])

X: real matrix containing the main data (the data to be
reweighted); rows are observations, columns are variables

w: real colvector containing base weights;
use w = 1 for unweighted data; if not scalar, w must have
the same number of rows as X

Xref: real matrix containing the reference data;
rows are observations, columns are variables; Xref must have the same
number of columns as X; if Xref only has a single row, it is
assumed to contain population averages

wref: real colvector containing base weights
for the reference data; use wref = 1 for unweighted data; if not
scalar, wref must have the same number of rows as Xref; if
Xref only has a single row, wref is assumed to contain the
population size

fast: real scalar indicating whether checks for
missing values and negative base weights should be skipped (to save computer
time); specify fast!=0 to skip the checks; omitted fast is
equivalent to fast=0; specify fast!=0 only if you are certain that
there are no missing values and that there are no negative base weights;
mm_ebalance() may break or return invalid results if either condition is violated

Specifying S.data() clears any results that may already exist in S.

Retrieve results

b = S.b() fitted coefficients (column vector)

a = S.a() normalizing intercept (scalar)

wbal = S.wbal() balancing weights: w * exp(Xb + a)

xb = S.xb() linear predictions: Xb + a

pr = S.pr() propensity scores: invlogit(Xb + a + ln(Wref/tau))

madj = S.madj() means of X after reweighting

wsum = S.wsum() total of balancing weights: sum(wbal)

loss = S.loss() balancing loss at final fit

bal = S.balanced() 1 if balance is achieved (loss < btol), 0 else

value = S.value() value of the optimization criterion at final fit

iter = S.iter() number of iterations of the optimization algorithm

conv = S.converged() 1 if the optimization algorithm converged, 0 else

IF_b = S.IF_b() influence functions of coefficients (main sample)

IFref_b = S.IFref_b() influence functions of coefficients (reference sample)

IF_a = S.IF_a() influence function of intercept (main sample)

IFref_a = S.IFref_a() influence function of intercept (reference sample)

Specifying any of the above functions will trigger estimation, if not already carried out.

Retrieve information on data

k = S.k() number of variables (columns) in X (number of coefficients)

omit = S.omit() column vector flagging collinear variables (omitted coefficients)

k_omit = S.k_omit() number of collinear variables (omitted coefficients)

X = S.X() data of main sample

w = S.w() base weights of main sample

N = S.N() number of rows in main sample

W = S.W() size (sum of weights) of main sample

m = S.m() means of X (before reweighting)

s = S.s() standard deviations of X

Xref = S.Xref() data of reference sample

wref = S.wref() base weights of reference sample

Nref = S.Nref() number of rows in reference sample

Wref = S.Wref() size (sum of weights) of reference sample

mref = S.mref() means of Xref

sref = S.sref() standard deviations of Xref

scale = S.scale() scales used for standardization

mu = S.mu() target values for means of reweighted X

tau = S.tau() target sum of balancing weight

Description

mm_ebalance() performs entropy balancing (Hainmueller 2012). The
goal of mm_ebalance() is to find a vector of weights such that the
means in the reweighted data of a given sample match the means in the data
of a reference sample (i.e., to find weights that balance the means between
the two samples) or, equivalently, to find weights that adjust the sample
means to known population values.

Estimation of the required coefficients is performed by calling Mata's
optimize(). Collinear terms will be ignored during
optimization. However, these terms will be taken into account when computing
the final balancing loss after optimization has completed.

In addition to the balancing weights and the coefficients,
mm_ebalance() also provides influence functions that are useful for
the computation of standard errors of the coefficients and for the correction
of standard errors of statistics that have been estimated from reweighted
data; see Jann (2021b),
which also provides details on the methods and formulas implemented in
mm_ebalance().

A wrapper for mm_ebalance() that obtains balancing weights in a single
line of code is provided as mm_wbal(). Furthermore, an
older function for entropy balancing with somewhat different
features is available as mm_ebal().

See ebalfit (Jann 2021a) for an easy to use Stata implementation
of entropy balancing that is based on mm_ebalance(). For an alternative
Stata implementation see ebalance by Hainmueller and Xu (2011, 2013).

Examples

Balance subsamples

. sysuse nlsw88, clear
. drop if missing(union, hours, ttl_exp, tenure)
. generate byte nonunion = 1 - union
. mata:
: X = st_data(., "hours ttl_exp tenure", "union")
: Xref = st_data(., "hours ttl_exp tenure", "nonunion")
: S = mm_ebalance()
: S.data(X, 1, Xref, 1)
: mean(Xref)', mean(X)', mean(X, S.wbal())'
: rows(Xref), rows(X), sum(S.wbal())
: S.b() (obtain coefficients)
: S.a() (obtain normalizing constant)
: S.loss() (obtain balancing loss)
: end

The balancing weights adjust the sample of unionized workers in a
way such that the means of working hours, work experience, and tenure are
the same as in the reference sample (non-unionized workers).

By default, the sum of the balancing weights will be equal to the size
of the reference sample.

Balance only a subset of the means and hold the other means fixed at their
original values:

. mata:
: S.adj(2) (balance work experience only)
: mean(Xref)', mean(X)', mean(X, S.wbal())'
: S.noadj(2) (do not balance work experience)
: mean(Xref)', mean(X)', mean(X, S.wbal())'
: end

Adjust sample to population

From census data you know that the population averages of working hours,
work experience, and tenure are 35, 10, and 5, respectively. The size of the
population is 10 million. You want to reweight your sample such that
it is in line with the population:

. sysuse nlsw88, clear
. drop if missing(hours, ttl_exp, tenure)
. mata:
: X = st_data(., "hours ttl_exp tenure")
: mu = (35, 10, 5)
: N = 1e7
: S = mm_ebalance()
: S.data(X, 1, mu, N)
: mean(X)', mean(X,S.wbal())'
: S.wsum()
: end

Source code

mm_ebalance.mata

References

Hainmueller, J. (2012). Entropy Balancing for Causal Effects: A
Multivariate Reweighting Method to Produce Balanced Samples in
Observational Studies. Political Analysis
20(1): 25-46. DOI: 10.1093/pan/mpr025

Hainmueller, J., Y. Xu (2011). EBALANCE: Stata module to perform Entropy
reweighting to create balanced samples. Statistical Software Components
S457326, Boston College Department of Economics. http://ideas.repec.org/c/boc/bocode/s457326.html.

Hainmueller, J., Y. Xu (2013). ebalance: A Stata Package for Entropy Balancing.
Journal of Statistical Software
54(7):1-18. DOI: 10.18637/jss.v054.i07

Jann, B. (2021a). ebalfit: Stata module to perform entropy balancing. Available
from http://github.com/benjann/ebalfit/.

Jann, B. (2021b). Entropy balancing as an estimation command. University of
Bern Social Sciences Working Papers 39. Available from
http://ideas.repec.org/p/bss/wpaper/39.html.

Author

Ben Jann, University of Bern, ben.jann@unibe.ch

Also see

Online: help for
[M-5] optimize(), moremata, mm_wbal(), mm_ebal(),
ebalfit (if installed)