Skip to contents

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 NULL for the first moments. This is the only route to those rows: the moments in balance_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 NULL for the family default of 1e-8. Energy balancing defaults to 1e-6 rather than to that family default because its quadratic form is indefinite: on a small sample the alternating-direction residual floors above 1e-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, whatever balancing.qp_backend names, 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 same max_iterations. When it does not, the fit reports the iterate of the original solve.

max_iterations

The maximum solver iterations, or NULL for the resolved default of 200000. The re-solve above is given the same cap, and when it converges the reported @iterations sums 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)