I am simulating a random-intercept logit model and everything is (mostly) working correctly except I can only figure out how to pass one "thing" out of the simulation loop. Here is a simplified version of my simulation and I've chosen to pass the actual (simulated) and fitted response means for each time-by-group stratum.
Notice at the bottom of the example I have a single-dataset version of the simulation which shows the other two objects I'd like to get for each rep of the simulation. But I can't seem to use the list() or c() functions inside the foreach() loop to combine all three types of results.
NOTE: I have reduced the number of subject, number of replications and eliminated some of the more interesting features that I am simulating, just to make a reprex that is a little more managable!
library(tidyverse)
library(lme4)
#> Loading required package: Matrix
#>
#> Attaching package: 'Matrix'
#> The following object is masked from 'package:tidyr':
#>
#> expand
library(parallel)
library(foreach)
#>
#> Attaching package: 'foreach'
#> The following objects are masked from 'package:purrr':
#>
#> accumulate, when
library(doParallel)
#> Loading required package: iterators
nsubj <- 100 # Total number of subjects, randomly split into two roughtly equal groups
nreps <- 20 # Number of repetitions of the simulation
par0 <- -5.0 # Overall Intercept
par0sd <- 2.0 # SD of random Intercepts
par1 <- 0.4 # Time effect (per unit)
par1sd <- 0.01 # Very small SD to make Time effect vary slightly by subj
par2 <- 1.0 # Difference in logit(y) when grp=1
par3 <- 0.05 # Effect of continuous time-varying covariate
set.seed(20)
cl<-makeCluster(4)
clusterExport(cl, c("nsubj", "nreps", "par0", "par1", "par0sd", "par1sd", "par2", "par3"))
clusterEvalQ(cl, require(dplyr))
#> [[1]]
#> [1] TRUE
#>
#> [[2]]
#> [1] TRUE
#>
#> [[3]]
#> [1] TRUE
#>
#> [[4]]
#> [1] TRUE
clusterEvalQ(cl, require(lme4))
#> [[1]]
#> [1] TRUE
#>
#> [[2]]
#> [1] TRUE
#>
#> [[3]]
#> [1] TRUE
#>
#> [[4]]
#> [1] TRUE
registerDoParallel(cl)
simres <- foreach (i=1:nreps,.combine='rbind') %dopar% {
ds1 <- data.frame(time=rep(0:2,nsubj),
subj=rep(1:nsubj,each=3),
grp=rep(rbinom(nsubj,1,0.5),each=3))
unique <- rnorm(nsubj,par0,par0sd)
ds2 <- mutate(ds1,
zvar=rnorm(n(),40,10),
logit=(unique[subj] + (rnorm(n(),par1,par1sd)*time) + (grp*par2)) + (par3*zvar),
prob=exp(logit)/(1+exp(logit)),
y=rbinom(n(),1,prob))
model <- glmer(y~time + grp + zvar + (1|subj),
data = ds2,
family = binomial,
control = glmerControl(optimizer = "bobyqa"),
nAGQ = 10)
cf_grp0 <- as.data.frame(cbind(select(ds2,time,grp),
fitted=predict(model,newdat=mutate(ds2,grp=0), type='response')))
cf_grp1 <- as.data.frame(cbind(select(ds2,time,grp),
fitted=predict(model,newdat=mutate(ds2,grp=1), type='response')))
fitted_means <- rbind(mean(filter(cf_grp0,time==0)$fitted),
mean(filter(cf_grp0,time==1)$fitted),
mean(filter(cf_grp0,time==2)$fitted),
mean(filter(cf_grp1,time==0)$fitted),
mean(filter(cf_grp1,time==1)$fitted),
mean(filter(cf_grp1,time==2)$fitted))
fitdat <- as.data.frame(cbind(fitted_means,c(0,1,2,0,1,2),c(0,0,0,1,1,1),rep(i,6)))
names(fitdat) <- c("fitted", "time", "grp", "simindex")
actdat <- ds2 %>% group_by(grp,time) %>% summarize(actual=mean(y))
merge(fitdat,actdat)
}
stopCluster(cl)
ds1 <- data.frame(time=rep(0:2,nsubj),
subj=rep(1:nsubj,each=3),
grp=rep(rbinom(nsubj,1,0.5),each=3))
unique <- rnorm(nsubj,par0,par0sd)
ds2 <- mutate(ds1,
zvar=rnorm(n(),40,10),
logit=(unique[subj] + (rnorm(n(),par1,par1sd)*time) + (grp*par2)) + (par3*zvar),
prob=exp(logit)/(1+exp(logit)),
y=rbinom(n(),1,prob))
model <- glmer(y~time + grp + zvar + (1|subj),
data = ds2,
family = binomial,
control = glmerControl(optimizer = "bobyqa"),
nAGQ = 10)
cf_grp0 <- as.data.frame(cbind(select(ds2,time,grp),
fitted=predict(model,newdat=mutate(ds2,grp=0), type='response')))
cf_grp1 <- as.data.frame(cbind(select(ds2,time,grp),
fitted=predict(model,newdat=mutate(ds2,grp=1), type='response')))
fitted_means <- rbind(mean(filter(cf_grp0,time==0)$fitted),
mean(filter(cf_grp0,time==1)$fitted),
mean(filter(cf_grp0,time==2)$fitted),
mean(filter(cf_grp1,time==0)$fitted),
mean(filter(cf_grp1,time==1)$fitted),
mean(filter(cf_grp1,time==2)$fitted))
fitdat <- as.data.frame(cbind(fitted_means,c(0,1,2,0,1,2),c(0,0,0,1,1,1)))
names(fitdat) <- c("fitted", "time", "grp")
actdat <- ds2 %>% group_by(grp,time) %>% summarize(actual=mean(y))
merge(fitdat,actdat)
#> time grp fitted actual
#> 1 0 0 0.1296945 0.1403509
#> 2 0 1 0.2694530 0.3488372
#> 3 1 0 0.1432779 0.1403509
#> 4 1 1 0.2917023 0.2325581
#> 5 2 0 0.1636548 0.2105263
#> 6 2 1 0.3223058 0.3488372
summary(model)$coefficients[1:4,1]
#> (Intercept) time grp zvar
#> -3.79556816 0.20677862 1.16840062 0.02806947
as.data.frame(VarCorr(model))[1,"sdcor"]
#> [1] 1.858803
Created on 2019-01-15 by the reprex package (v0.2.1)