bw_energy() specifies energy balancing for balance(). The weights
minimize the energy distance between the reweighted exposure groups and a
target sample, subject to a simplex-type constraint set, so the reweighting
improves multivariate covariate balance without positing a propensity model.
Energy balancing supports binary, categorical, and continuous exposures.
Usage
bw_energy(
...,
distance = c("scaled_euclidean", "mahalanobis", "euclidean"),
improved = TRUE,
weight_penalty = 1e-04,
min_weight = 1e-08,
distribution_moments = NULL,
dimension_adjustment = TRUE,
convergence_tolerance = 1e-06,
max_iterations = NULL
)Arguments
- ...
Reserved for future extensions; must be empty. Tuning parameters must be passed by name.
- distance
The covariate distance definition the energy objective is built on, one of
"scaled_euclidean"(each covariate centered at its weighted mean and divided by its weighted standard deviation),"mahalanobis", or"euclidean".- improved
Whether to add the between-group energy distance of the improved variant for the average treatment effect with a discrete exposure.
- weight_penalty
The L2 penalty on the weights, which stabilizes the quadratic program. For a continuous exposure it is also what sets the residual exposure-covariate correlation, as the details section explains.
- min_weight
The smallest permitted weight. The reported weights average one within each exposure group, so a floor approaching one leaves almost no room above it: the weight spread shrinks in proportion to the headroom
1 - min_weight, and the fit degenerates smoothly into uniform weights and reports the balance uniform weights achieve. Nothing warns at that boundary, because the problem stays feasible and the solution is a real one.bw_sbw(), whose tolerances are hard constraints rather than an objective, refuses the same floor as infeasible instead.- distribution_moments
For a continuous exposure, the number of exposure and covariate marginal moments held equal to the sample under the base measure, or
NULLfor the first moments. This is the only route to those rows: themomentsinbalance_terms()asks for exposure-covariate correlation constraints instead and leaves the marginals here. Energy balancing carries no base weights, so the base measure is the sampling weights, and without them the marginals are held equal to the unweighted sample.- dimension_adjustment
For a continuous exposure, whether to weight the covariate energy distance by the covariate dimensionality adjustment.
- convergence_tolerance
The quadratic-program solver tolerance, which the solver applies as both its absolute and its relative tolerance, or
NULLfor the family default of1e-8. Energy balancing defaults to1e-6rather than to that family default because its quadratic form is indefinite: on a small sample the alternating-direction residual floors above1e-8, and a run that keeps going past that floor walks away from the optimum instead of stalling at it. The energy objective always solves through the alternating-direction backend, whateverbalancing.qp_backendnames, so there is no backend to choose here: a tolerance below what the problem can reach spends the full iteration cap, then warns and reports the iterate of a re-solve at a tolerance the problem does reach, provided that re-solve converges within the samemax_iterations. When it does not, the fit reports the iterate of the original solve.- max_iterations
The maximum solver iterations, or
NULLfor the resolved default of 200000. The re-solve above is given the same cap, and when it converges the reported@iterationssums the two solves, so an energy fit that could not reach its tolerance can report more iterations than this. The refinement passes of a continuous fit with a positive tolerance are summed the same way, each pass being a solve of its own.
Value
An bw_energy specification, a balance_method.
Details
For a binary or categorical exposure the objective is the sum of each group's
energy distance to the target sample. The improved variant for the average
treatment effect adds the between-group energy distance, which balances the
groups against one another as well as against the sample. A focal estimand
reweights the non-focal groups toward the focal group, whose units keep their
base weight. The energy distance is built from a pairwise covariate distance
matrix; distance selects how that matrix is formed.
For a continuous exposure the objective is the weighted distance covariance
between the exposure and the covariates, following Huling, Greifer, and Chen,
plus the marginal energy distances of the weighted exposure and covariate
distributions. distribution_moments sets how many exposure and covariate
marginal moments are held equal to the sample under the base measure, and
dimension_adjustment reweights the covariate energy distance by the
covariate dimensionality.
The two knobs a continuous fit carries are separate. moments in
balance_terms() adds a constraint that holds the weighted correlation of
the exposure with each covariate power within its tolerance, which defaults
to zero, and distribution_moments pins the marginal moments of the
exposure and of the covariates. Neither sets the other: a fit that wants
both asks for both. The correlation rows are held within the tolerance
balance_terms() carries, and reaching that band takes more than one solve.
The quadratic program bounds a linearized correlation whose exposure and
covariate scales are fixed at the sample, and the spread of energy weights
shrinks both weighted standard deviations, so a single solve at the requested
band overshoots it: a band of 0.05 lands between 0.070 and 0.086 at 200 to
1000 observations. The fit therefore tightens the bound it hands the program
and re-solves, up to eight passes, until the reported correlation sits inside
the band. A band of 0.05 took two passes at 350 and at 1000 observations, so
it costs about two solves against the one the same fit at exact balance takes,
exact balance having nothing to tighten. A band the passes cannot reach is
reported at its last iterate, and the balance warning judges it as it judges
any other fit.
Without those rows the continuous objective targets distributional
independence between the exposure and the covariates rather than zero
correlations, and it does not drive the correlations to zero. A residual
weighted correlation of roughly 0.1 to 0.3 is ordinary at a few hundred to a
few thousand observations. What holds it up is weight_penalty, which trades that
residual against effective sample size: at its default of 1e-4 the penalty
term is about three quarters of the objective at 1000 observations, leaving a
largest correlation near 0.22 to 0.25 at an effective sample size near 71
percent, while a penalty of zero brings the correlation down to 0.05 to 0.07
and the effective sample size down to about 20 percent. Ask for
balance_terms(moments = 1) to remove the correlation outright, at a cost in
effective sample size of its own.
Energy balancing belongs to the quadratic-program family, which has no
estimating equations, so a fit produces no estimating-equations container and
the tolerance in balance_terms() relaxes the constraints a fit added rather
than selecting an inexact solver. A tolerance supplied without those
constraints has nothing to relax, so it is warned and ignored, and the balance
table reports the tolerance the fit enforced, which is zero.
References
Huling, J. D. and Mak, S. (2024). Energy balancing of covariate distributions. Journal of Causal Inference, 12(1), 20220029.
Huling, J. D., Greifer, N., and Chen, G. (2024). Independence weights for causal inference with continuous treatments. Journal of the American Statistical Association, 119(546), 1657-1670.
Examples
n <- 200
x1 <- rnorm(n)
x2 <- rnorm(n)
df <- data.frame(
exposure = rbinom(n, 1, plogis(0.5 * x1 - 0.5 * x2)),
x1 = x1,
x2 = x2
)
fit <- balance(df, exposure, c(x1, x2), method = bw_energy())
#> ℹ Treating `.exposure` as binary
fit
#>
#> ── Energy balancing ────────────────────────────────────────────────────────────
#> Exposure: "exposure" (binary)
#> Estimand: "ate"
#> Observations: 200
#> Solver: converged in 50 iterations
#> Constraints: 2 terms (tolerance 0)
#> Largest imbalance: 0.00579 (standardized mean difference)
