# How to perform fine balance matching in R for several covariates?

I want to use fine balance matching to balance the marginal distribution of some covariates, so that it will be less stringent than exact matching.

Below are some options I found:

The fine() function in DOS2 package only works for fine balancing one covariate.

The rcbalance() function in rcbalance package seems suitable. However, the example given in the R document does not work. Not all treated units are matched with a control unit. Not sure if there is an error there.

cardmatch() function in designmatch package seems to use fine balance matching, but it is for cardinality matching. I am not sure about the difference and it seems complicated.

Could you give some suggestions on fine balance matching for several categorical covariates? Thanks.

Update: Adding calip.option = 'none' will make the example for rcbalance() to work. I think I will try to use rcbalance().

rcbalance() doesn't actually produce fine balance on the included covariates; it produces "refined" balance, which is slightly different in that it balances based on a priority list rather than exactly fine balancing each requested covariate.

What you want is cardinality matching, which allows you to specify any balance constraint that the match should solve, including fine balance. Cardinality matching is less complicated than it sounds; an optimizer finds the largest matched sample that satisfies the supplied balance constraints, without pairing individuals. cardmatch() in the designmatch package is one way to do so and can have excellent performance due to using a fast approximation to the cardinality match solution. In MatchIt, setting method = "cardinality" in a call to matchit() is another way to perform cardinality matching. For both packages, you need to supply a balance tolerance for the (standardized) mean differences of each covariate; to implement fine balancing, you simply set the balance constraint for each categorical variable you want fine balance on to 0. In MatchIt, the code would look like the following:

m <- matchit(A ~ X1 + X2 + F1 + F2, data = data, method = "cardinality",
tols = c(X1 = .05, X2 = .05, F1 = 0, F2 = 0))


This requests balance on covariates X1, X2, F1, and F2, with fine balance requested for F1 and F2 and standardized mean differences no greater than .05 for X1 and X2 with respect to treatment A. If it is impossible to satisfy this balance constraint by keeping all treated units and retaining an equal number of treated and control units, some treated units will be discarded to satisfy the constraints. To request that all treated units be kept but to allow the number of control units not to equal the number of treated units, you can set ratio = NA in the call to matchit(). See an explanation of cardinality matching here and the documentation for matchit() with method = "cardinality" here.

• thank you so much! this is very helpful!
– hehe
May 2 at 19:06
• It seems when ratio is set to NA, the procedure takes a really long time and is not feasible to finish even when I set time=600.
– hehe
Jun 13 at 3:58
• Also the cardinality matching did not give subclass ID in the output. It may be OK not to use cluster robust SE when ratio is 1. But for variable ratio, it may be problem?
– hehe
Jun 13 at 4:09
• Are you using solver = "gurobi"? That can often work with hard to solve problems. Gurobi is proprietary but free for academic use. Cardinality matching does not involve pairs so there will be no subclass ID. You should not use cluster-robust SEs and instead use regular robust SE.
– Noah
Jun 13 at 7:01
• You would use the following code: coeftest(fit1, vcov. = vcovHC). You should use robust SEs even with 1:1 matching unless you know the variance of the outcome is the same in both groups (it isn't). It is standard practice after matching and weighting.
– Noah
Jun 28 at 3:55