I have a data set of ~20,000 cases and ~50,000 controls. Each case has been preliminarily matched with 3 controls using a join process in SQL that asked for an exact match on some covariates (e.g., a binary variable for whether the person was enrolled in the study in 2019) and allowed a match within a range for other covariates (e.g., total days enrolled within +/- 25 days). A control could thus be listed as a possible control for more than one case.
In R, I would like to select the control for each case from each case's 3 possible matches while ensuring two things: 1) controls are not repeated, and 2) for cases for which there is no exact match, that the control is matched as closely as possible on the covariates.
I think the approach I need is to group the data by the case_id and select the control_id from each group where the difference between the covariates is minimized. The wrinkle is that I need to ensure that once a control has been selected for a case in one group, it cannot be used as the control for a second case, no matter how good the covariate match is.
Here is some sample data:
case_id <- c(1,1,1,2,2,2,3,3,3,4,4,4)
control_id <- c(5,14,7,8,9,10,11,12,13,14,15,5)
case_enrolled_2019 <- c(1,1,1,0,0,0,0,0,0,1,1,1)
control_enrolled_2019 <- c(1,1,1,0,0,0,0,0,0,1,1,1)
case_enrollment_count <- c(1,1,1,3,3,3,1,1,1,1,1,1)
control_enrollment_count <- c(2,1,1,3,3,3,1,1,1,1,1,2)
case_enrolled_days <- c(300,300,300,200,200,200,600,600,600,300,300,300)
control_enrolled_days <- c(300,300,280,200,200,210,601,610,598,300,301,300)
cbind(case_id, control_id, case_enrolled_2019, control_enrolled_2019, case_enrollment_count, control_enrollment_count, case_enrolled_days, control_enrolled_days)
I need output like:
case_id <- c(1,2,3,4)
control_id <- c(14,8,11,15)
case_enrolled_2019 <- c(1,0,0,1)
control_enrolled_2019 <- c(1,0,0,1)
case_enrollment_count <- c(1,3,1,1)
control_enrollment_count <- c(1,3,1,1)
case_enrolled_days <- c(300,200,600,300)
control_enrolled_days <- c(300,200,601,301)
cbind(case_id, control_id, case_enrolled_2019, control_enrolled_2019, case_enrollment_count, control_enrollment_count, case_enrolled_days, control_enrolled_days)