Yes, the mice package can make imputations for data like this.
In the example code below, I first copy any partially observed data into the rest of that idnum
. Next I transform the data from "long" into "wide" format. There will be 1 row for each idnum
. The idnum
, bmi
, and gender
variables will stay as they are, but the eye
and cct
variables will be combined into cct_L
and cct_R
. After that we can run the mice
function as usual, although in this example data we'll need to tweak which variables are used as predictors of the others, otherwise the models will be over-specified.
After the imputations are created you can transform back into the longer format with pivot_longer
. I find it's easiest to do that inside the with
call that fits the analysis to each imputed dataset.
library(tidyverse)
library(mice)
dat <- data.frame(
idnum = c(101,101,102,102,103,103,104,104,105,105,106,106),
eye = c("L","R","L","R","L","R","L","R","L","R","L","R"),
bmi = c(23,NA,26,26,22,NA,18,18,20,20,NA,NA),
cct = c(21.3,20.1,18.3,NA,20.1,19,22.4,21,19,NA,18.3,17.8),
gender = c("male","male","female",NA,"male",NA,"female","female","male","male",NA,NA))
dat$gender <- factor(dat$gender)
dat$eye <- factor(dat$eye)
# Match all observed data
check_na <- function(x) {
stopifnot(length(x) == 2)
if(!is.na(x[1]) & !is.na(x[2])) {
if(x[1] == x[2]) {
return(x)
} else {
stop("two values for the same idnum don't match")
}
}
if(is.na(x[1]) & is.na(x[2])) {
return(x)
}
if(!is.na(x[1]) & is.na(x[2])) {
return(c(x[1],x[1]))
}
if(is.na(x[1]) & !is.na(x[2])) {
return(c(x[2],x[2]))
}
stop("should never reach here")
}
dat_fixed <- dat
for(i in unique(dat$idnum)) {
dat_fixed[dat_fixed$idnum == i,]$bmi <-
check_na(dat_fixed[dat_fixed$idnum == i,]$bmi)
dat_fixed[dat_fixed$idnum == i,]$gender <-
check_na(dat_fixed[dat_fixed$idnum == i,]$gender)
}
# Transform data into wide format
dat_wide <-
pivot_wider(dat_fixed,
id_cols = c("idnum","bmi","gender"),
names_from = "eye",
names_prefix = "cct_",
values_from = "cct")
dat_wide
#> # A tibble: 6 x 5
#> idnum bmi gender cct_L cct_R
#> <dbl> <dbl> <fct> <dbl> <dbl>
#> 1 101 23 male 21.3 20.1
#> 2 102 26 female 18.3 NA
#> 3 103 22 male 20.1 19
#> 4 104 18 female 22.4 21
#> 5 105 20 male 19 NA
#> 6 106 NA <NA> 18.3 17.8
# Specify which variables to use for imputations
pred <- quickpred(dat_wide)
pred[,] <- 0
pred["cct_R",c("bmi","cct_L")] <- 1
pred[c("bmi","gender"),c("bmi","gender")] <- 1
diag(pred) <- 0
# Make imputations
imps <- mice(dat_wide,
m = 5,
seed = 123,
predictorMatrix = pred,
printFlag = FALSE)
# View one of the imputed datasets
complete(imps, action = 1)
#> idnum bmi gender cct_L cct_R
#> 1 101 23 male 21.3 20.1
#> 2 102 26 female 18.3 20.1
#> 3 103 22 male 20.1 19.0
#> 4 104 18 female 22.4 21.0
#> 5 105 20 male 19.0 20.1
#> 6 106 23 female 18.3 17.8