| optweight | R Documentation |
Estimates stable balancing weights for the supplied treatments and covariates. The degree of balance for each covariate is specified by tols and the target population can be specified with targets or estimand. See Zubizarreta (2015) and Wang & Zubizarreta (2020) for details of the properties of the weights and the methods used to fit them.
optweight(
formula,
data = NULL,
tols = 0,
estimand = "ATE",
targets = NULL,
target.tols = 0,
s.weights = NULL,
b.weights = NULL,
focal = NULL,
norm = "l2",
min.w = 1e-08,
verbose = FALSE,
...
)
optweight.fit(
covs,
treat,
tols = 0,
estimand = "ATE",
targets = NULL,
target.tols = 0,
s.weights = NULL,
b.weights = NULL,
focal = NULL,
norm = "l2",
std.binary = FALSE,
std.cont = TRUE,
min.w = 1e-08,
verbose = FALSE,
solver = NULL,
...
)
formula |
a formula with a treatment variable on the left hand side and the covariates to be balanced on the right hand side, or a list thereof. Interactions and functions of covariates are allowed. |
data |
an optional data set in the form of a data frame that contains the variables in |
tols |
a vector of balance tolerance values for each covariate. The resulting weighted balance statistics will be at least as small as these values. If only one value is supplied, it will be applied to all covariates. Can also be the output of a call to |
estimand |
a string containing the desired estimand, which determines the target population. For binary treatments, can be "ATE", "ATT", "ATC", or |
targets |
an optional vector of target population mean values for each covariate. The resulting weights ensure the midpoint between group means are within |
target.tols |
a vector of target balance tolerance values for each covariate. For binary and multi-category treatments, the average of each pair of means will be at most as far from the target means as these values. Can also be the output of a call to |
s.weights |
a vector of sampling weights. For |
b.weights |
a vector of base weights. If supplied, the desired norm of the distance between the estimated weights and the base weights is minimized. For |
focal |
when multi-category treatments are used and |
norm |
|
min.w |
|
verbose |
|
... |
for |
covs |
a numeric matrix of covariates to be balanced. |
treat |
a vector of treatment statuses. Non-numeric (i.e., factor or character) vectors are allowed. |
std.binary, std.cont |
|
solver |
string; the name of the optimization solver to use. Allowable options depend on |
optweight() is the primary user-facing function for estimating stable balancing weights. The optimization is performed by the lower-level function optweight.fit(), which transforms the inputs into the required inputs for the optimization functions and then supplies the outputs (the weights, dual variables, and convergence information) back to optweight(). Little processing of inputs is performed by optweight.fit(), as this is normally handled by optweight().
For binary and multi-category treatments, weights are estimated so that the weighted mean differences of the covariates are within the given tolerance thresholds controlled by tols and target.tols (unless std.binary or std.cont are TRUE, in which case standardized mean differences are considered for binary and continuous variables, respectively). For a covariate x with specified balance tolerance \delta and target tolerance \varepsilon, the weighted means of each each group will be within \delta of each other, and the midpoint between the weighted group means will be with \varepsilon of the target means. More specifically, the constraints are specified as follows:
\left| \bar{x}^w_1 - \bar{x}^w_0 \right| \le \delta \\
\left| \frac{\bar{x}^w_1 + \bar{x}^w_0}{2} - \bar{x}^* \right| \le \varepsilon
where \bar{x}^w_1 and \bar{x}^w_0 are the weighted means of covariate x for treatment groups 1 and 0, respectively, and \bar{x}^* is the target mean for that covariate. \delta corresponds to tols, and \varepsilon corresponds to target.tols. Setting a covariate's value of target.tols to Inf or its target to NA both serve to remove the second constraint, as is done in Barnard et al. (2025).
If standardized tolerance values are requested, the standardization factor corresponds to the estimand requested: when the ATE is requested or a target population specified, the standardization factor is the square root of the average variance for that covariate across treatment groups, and when the ATT or ATC are requested, the standardization factor is the standard deviation of the covariate in the focal group. The standardization factor is computed accounting for s.weights.
Target and balance constraints are applied to the product of the estimated weights and the sampling weights. In addition, the sum of the product of the estimated weights and the sampling weights is constrained to be equal to the sum of the product of the base weights and sampling weights. For binary and multi-category treatments, these constraints apply within each treatment group.
For continuous treatments, weights are estimated so that the weighted correlation between the treatment and each covariate is within the specified tolerance threshold. The means of the weighted covariates and treatment are restricted to be exactly equal to those of the target population to ensure generalizability to the desired target population, regardless of tols or target.tols. The weighted correlation is computed as the weighted covariance divided by the product of the unweighted standard deviations. The means used to center the variables in computing the covariance are those specified in the target population.
normThe objective function for the optimization problem is f\left(\mathbf{w}, \mathbf{b},\mathbf{s}\right), where \mathbf{w}=\{w_1, \dots, w_n\} are the estimated weights, \mathbf{s}=\{s_1, \dots, s_n\} are sampling weights (supplied by s.weights), and \mathbf{b}=\{b_1, \dots, b_n\} are base weights (supplied by b.weights). The norm argument determines f(.,.,.), as detailed below:
when norm = "l2", f\left(\mathbf{w}, \mathbf{b},\mathbf{s}\right) = \frac{1}{n} \sum_i {s_i(w_i - b_i)^2}
when norm = "l1", f\left(\mathbf{w}, \mathbf{b},\mathbf{s}\right) = \frac{1}{n} \sum_i {s_i \vert w_i - b_i \vert}
when norm = "linf", f\left(\mathbf{w}, \mathbf{b},\mathbf{s}\right) = \max_i {\vert w_i - b_i \vert}
when norm = "entropy", f\left(\mathbf{w}, \mathbf{b},\mathbf{s}\right) = \frac{1}{n} \sum_i {s_i w_i \log \frac{w_i}{b_i}}
when norm = "log", f\left(\mathbf{w}, \mathbf{b},\mathbf{s}\right) = \frac{1}{n} \sum_i {-s_i \log \frac{w_i}{b_i}}
By default, s.weights and b.weights are set to 1 for all units unless supplied. b.weights must be positive when norm is "entropy" or "log", and norm = "linf" cannot be used when s.weights are supplied.
When norm = "l2" and both s.weights and b.weights are NULL, weights are estimated to maximize the effective sample size. When norm = "entropy", the estimated weights are equivalent to entropy balancing weights (Källberg & Waernbaum, 2023). When norm = "log", b.weights are ignored in the optimization, as they do not affect the estimated weights.
Two types of constraints may be associated with each covariate: target constraints and balance constraints, controlled by target.tols and tols, respectively. In the duals component of the output, each covariate has a dual variable for each constraint placed on it. The dual variable for each constraint is the instantaneous rate of change of the objective function at the optimum corresponding to a change in the constraint. Because this relationship is not linear, large changes in the constraint will not exactly map onto corresponding changes in the objective function at the optimum, but will be close for small changes in the constraint. For example, for a covariate with a balance constraint of .01 and a corresponding dual variable of 40, increasing (i.e., relaxing) the constraint to .025 will decrease the value of the objective function at the optimum by approximately (.025 - .01) * 40 = .6.
For factor variables, optweight() takes the sum of the absolute dual variables for the constraints for all levels and reports it as the the single dual variable for the variable itself. This summed dual variable works the same way as dual variables for continuous variables do.
An additional dual variable is computed for the constraint on the range of the weights, controlled by min.w. A high dual variable for this constraint implies that decreasing min.w will decrease the value of the objective function at the optimum.
solverThe solver argument controls which optimization solver is used. Different solvers are compatible with each norm. See the table below for allowable options, which package they require, which function does the solving, and which function controls the settings.
solver | norm | Package | Solver function | Settings function |
"osqp" | "l2", "l1", "linf" | osqp | osqp::solve_osqp() | osqp::osqpSettings() |
"highs" | "l2", "l1", "linf" | highs | \pkgfunhighshighs_solve | \pkgfunhighshighs_control / \pkgfunhighshighs_available_solver_options |
"lpsolve" | "l1", "linf" | lpSolve | \pkgfunlpSolvelp | . |
"scs" | "entropy", "log" | scs | \pkgfunscsscs | \pkgfunscsscs_control |
"clarabel" | "entropy", "log" | clarabel | \pkgfunclarabelclarabel | \pkgfunclarabelclarabel_control |
Note that "lpsolve" can only be used when min.w is nonnegative.
The default solver for each norm is as follows:
norm | Default solver |
"l2" | "osqp" |
"l1" | "highs" |
"linf" | "highs" |
"entropy" | "scs" |
"log" | "scs" |
If the package corresponding to a default solver is not installed but the package for a different eligible solver is, that will be used. Otherwise, you will be asked to install the required package. osqp is required for optweight, and so will be the default for the "l1" and "linf" norms if highs is not installed. The default package is the one has shown good performance for the given norm in informal testing; generally, all eligible solvers perform about equally well in terms of accuracy but differ in time taken.
Sometimes the optimization will fail to converge at a solution. There are a variety of reasons why this might happen, which include that the constraints are nearly impossible to satisfy or that the optimization surface is relatively flat. It can be hard to know the exact cause or how to solve it, but this section offers some solutions one might try. Typically, solutions can be found most easily when using the "l2" norm; other norms, especially "linf" and "l1", are more likely to see problems.
Rarely is the problem too few iterations, though this is possible. Most problems can be solved in the default 200,000 iterations, but sometimes it can help to increase this number with the max_iter argument. Usually, though, this just ends up taking more time without a solution found.
If the problem is that the constraints are too tight, it can be helpful to loosen the constraints. Sometimes examining the dual variables of a solution that has failed to converge can reveal which constraints are causing the problem. An extreme value of a dual variable typically suggests that its corresponding constraint is one cause of the failure to converge.
Sometimes a suboptimal solution is possible; such a solution does not satisfy the constraints exactly but will come pretty close. To allow these solutions, the argument eps can be increased to larger values. This is more likely to occur when s.weights are supplied.
Sometimes using a different solver can improve performance. Using the default solver for each norm, as described above, can reduce the probability of convergence failures.
For optweight(), an optweight object with the following elements:
weights |
The estimated weights, one for each unit. |
treat |
The values of the treatment variable. |
covs |
The covariates used in the fitting. Only includes the raw covariates, which may have been altered in the fitting process. |
s.weights |
The provided sampling weights. |
b.weights |
The provided base weights. |
estimand |
The estimand requested. |
focal |
The focal variable if the ATT was requested with a multi-category treatment. |
call |
The function call. |
tols |
The balance tolerance values for each covariate. |
target.tols |
The target balance tolerance values for each covariate. |
duals |
A data.frame containing the dual variables for each covariate. See Details for interpretation of these values. |
info |
A list containing information about the performance of the optimization at termination. |
norm |
The |
solver |
The |
For optweight.fit(), an optweight.fit object with the following elements:
w |
The estimated weights, one for each unit. |
duals |
A data.frame containing the dual variables for each covariate. |
info |
A list containing information about the performance of the optimization at termination. |
norm |
The |
solver |
The |
Barnard, M., Huling, J. D., & Wolfson, J. (2025). Partially Retargeted Balancing Weights for Causal Effect Estimation Under Positivity Violations (No. arXiv:2510.22072). arXiv. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.48550/arXiv.2510.22072")}
Chattopadhyay, A., Cohn, E. R., & Zubizarreta, J. R. (2024). One-Step Weighting to Generalize and Transport Treatment Effect Estimates to a Target Population. The American Statistician, 78(3), 280–289. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1080/00031305.2023.2267598")}
de los Angeles Resa, M., & Zubizarreta, J. R. (2020). Direct and Stable Weight Adjustment in Non-Experimental Studies With Multivalued Treatments: Analysis of the Effect of an Earthquake on Post-Traumatic Stress. Journal of the Royal Statistical Society Series A: Statistics in Society, 183(4), 1387–1410. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1111/rssa.12561")}
Källberg, D., & Waernbaum, I. (2023). Large Sample Properties of Entropy Balancing Estimators of Average Causal Effects. Econometrics and Statistics. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1016/j.ecosta.2023.11.004")}
Wang, Y., & Zubizarreta, J. R. (2020). Minimal dispersion approximately balancing weights: Asymptotic properties and practical considerations. Biometrika, 107(1), 93–105. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1093/biomet/asz050")}
Zubizarreta, J. R. (2015). Stable Weights that Balance Covariates for Estimation With Incomplete Outcome Data. Journal of the American Statistical Association, 110(511), 910–922. \Sexpr[results=rd]{tools:::Rd_expr_doi("10.1080/01621459.2015.1023805")}
optweightMV() for estimating stable balancing weights for multivariate (i.e., multiple) treatments simultaneously.
sbw, which was the inspiration for this package and provides some additional functionality for binary treatments.
WeightIt, which provides a simplified interface to optweight() and a more efficient implementation of entropy balancing.
library("cobalt")
data("lalonde", package = "cobalt")
# Balancing covariates between treatment groups (binary)
(ow1 <- optweight(treat ~ age + educ + married +
nodegree + re74,
data = lalonde,
tols = c(.01, .02, .03, .04, .05),
estimand = "ATE"))
bal.tab(ow1)
# Exactly balancing covariates with respect to
# race (multi-category)
(ow2 <- optweight(race ~ age + educ + married +
nodegree + re74,
data = lalonde,
tols = 0,
estimand = "ATT",
focal = "black"))
bal.tab(ow2)
# Balancing covariates between treatment groups (binary)
# and requesting a specified target population
targets <- process_targets(~ age + educ + married +
nodegree + re74,
data = lalonde,
targets = c(26, 12, .4, .5,
1000))
(ow3a <- optweight(treat ~ age + educ + married +
nodegree + re74,
data = lalonde,
targets = targets,
estimand = NULL))
bal.tab(ow3a, disp.means = TRUE)
# Balancing covariates between treatment groups (binary)
# and requesting a specified target population, allowing
# for approximate target balance
(ow3b <- optweight(treat ~ age + educ + married +
nodegree + re74,
data = lalonde,
targets = targets,
estimand = NULL,
target.tols = .05))
bal.tab(ow3b, disp.means = TRUE)
# Balancing covariates between treatment groups (binary)
# and not requesting a target population
(ow3c <- optweight(treat ~ age + educ + married +
nodegree + re74,
data = lalonde,
targets = NULL,
estimand = NULL))
bal.tab(ow3c, disp.means = TRUE)
# Using a different norm
(ow1b <- optweight(treat ~ age + educ + married +
nodegree + re74,
data = lalonde,
tols = c(.01, .02, .03, .04, .05),
estimand = "ATE",
norm = "l1"))
summary(ow1b, weight.range = FALSE)
summary(ow1, weight.range = FALSE)
# Allowing for negative weights
ow4 <- optweight(treat ~ age + educ + married + race +
nodegree + re74 + re75,
data = lalonde,
estimand = "ATE",
min.w = -Inf)
summary(ow4)
# Using `optweight.fit()`
treat <- lalonde$treat
covs <- splitfactor(lalonde[2:8], drop.first = "if2")
ow.fit <- optweight.fit(covs,
treat = treat,
tols = .02,
estimand = "ATE",
norm = "l2")
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.