Использование jags.parallel изнутри функции (ошибка языка R в get(name, envir = envir): объект 'y' не найден)

Использование jags.parallel из командной строки или сценария работает нормально. Я могу запустить этот модифицированный пример с http://www.inside-r.org/packages/cran/R2jags/docs/jags просто отлично

# An example model file is given in:
  model.file <- system.file(package="R2jags", "model", "schools.txt")
#=================#
# initialization  #
#=================#

  # data
  J <- 8.0
  y <- c(28.4,7.9,-2.8,6.8,-0.6,0.6,18.0,12.2)
  sd <- c(14.9,10.2,16.3,11.0,9.4,11.4,10.4,17.6)

  jags.data <- list("y","sd","J")
  jags.params <- c("mu","sigma","theta")
  jags.inits <- function(){
    list("mu"=rnorm(1),"sigma"=runif(1),"theta"=rnorm(J))
  }


#===============================#
# RUN jags and postprocessing   #
#===============================#
#  jagsfit <- jags(data=jags.data, inits=jags.inits, jags.params, 
#    n.iter=5000, model.file=model.file)

  # Run jags parallely, no progress bar. R may be frozen for a while, 
  # Be patient. Currenlty update afterward does not run parallelly

  print("Running Parallel") 
  jagsfit <- jags.parallel(data=jags.data, inits=jags.inits, jags.params, 
    n.iter=5000, model.file=model.file)

Однако, если я оберну это в функцию

testparallel <- functions(out){
# An example model file is given in:
    .
    .
    .
jagsfit <- jags.parallel(data=jags.data, inits=jags.inits, jags.params, 
  n.iter=5000, model.file=model.file)
print(out)
return(jagsfit)
}

Затем я получаю сообщение об ошибке: Ошибка в get(name, envir = envir): объект 'y' не найден. На основании найденного здесь я знаю, что это проблема среды, экспортируемой в кластер, и я исправил ее, изменив

J <- 8.0
y <- c(28.4,7.9,-2.8,6.8,-0.6,0.6,18.0,12.2)
sd <- c(14.9,10.2,16.3,11.0,9.4,11.4,10.4,17.6)

в

  assign("J",8.0,envir=globalenv()) 
  assign("y",c(28.4,7.9,-2.8,6.8,-0.6,0.6,18.0,12.2),envir=globalenv()) 
  assign("sd",c(14.9,10.2,16.3,11.0,9.4,11.4,10.4,17.6),envir=globalenv()) 

Есть ли лучший способ обойти это?

Спасибо грег

PS

Я работаю над этим кодом для кого-то другого, поэтому я не хочу менять вещи в пакете R2jags, чтобы позволить мне перейти в среду для экспорта, хотя я планирую предложить его авторам пакета.

4 ответа

Решение

Итак, я связался с автором R2jags, и он добавил дополнительный аргумент в jags.parallel, который позволяет передавать envir, который затем передается на clusterExport.

Это хорошо работает, за исключением того, что допускает конфликты между именем моих данных и переменными в функции jags.parallel.

Если вы интенсивно используете JAGS параллельно, я могу предложить вам посмотреть пакет rjags в сочетании с пакетом dclone, Я думаю dclone действительно мощный, потому что синтаксис был точно таким же, как rjags, Я никогда не видел твоей проблемы с этим пакетом.

Если вы хотите использовать R2jags Я думаю, что вам нужно передать ваши переменные и функцию init работникам с помощью функции:

clusterExport(cl, list("jags.data", "jags.params", "jags.inits"))

Без изменения кода R2jagsэти переменные данных можно по-прежнему проще назначать глобальной среде, используя list2env,

Очевидно, существует опасение, что эти имена переменных могут быть перезаписаны в глобальной среде, но вы, вероятно, можете это контролировать.

Ниже приведен тот же код, что и в примере, приведенном в исходном сообщении, за исключением того, что я поместил данные в список и отправил данные этого списка в глобальную среду, используя list2env функция. (Также я вынул неиспользуемую переменную "out" в функции.) Это в настоящее время работает нормально для меня; вам, возможно, придется добавить больше цепочек и / или больше итераций, чтобы увидеть параллелизм в действии.

testparallel <- function(){

    library(R2jags)

    model.file <- system.file(package="R2jags", "model", "schools.txt")

    # Make a list of the data with named items.
    jags.data.v2 <- list(
        J=8.0, 
        y=c(28.4,7.9,-2.8,6.8,-0.6,0.6,18.0,12.2),
        sd=c(14.9,10.2,16.3,11.0,9.4,11.4,10.4,17.6) )

    # Store all that data explicitly in the globalenv() as
    # was previosly suggesting using the assign(...) function.
    # This will do that for you.
    # Now R2jags will have access to the data without you having 
    # to explicitly "assign" each to the globalenv.
    list2env( jags.data.v2, envir=globalenv() )

    jags.params <- c("mu","sigma","theta")
    jags.inits <- function(){
        list("mu"=rnorm(1),"sigma"=runif(1),"theta"=rnorm(J))
    }

    jagsfit <- jags.parallel(
        data=names(jags.data.v2), 
        inits=jags.inits, 
        jags.params, 
        n.iter=5000, 
        model.file=model.file)

    return(jagsfit)
}

По сути, это то, что делает r2jags, но он переписан, чтобы вы могли вручную помещать эти переменные в среду с помощью функцииusterExport(), которая загружает переменные в пустой сеанс R, настроенный отдельно для каждого кластера:

      jinits <- function(){list(.RNG.name = 'lecuyer::RngStream',
                            .RNG.seed = round(1e+06*runif(1)))}
cl <- makeCluster(mcmc_params$nchains,methods=F, type="PSOCK")
JAGSmod <- function(seed){
      set.seed(seed) #note this affects jinits, but not rjags itself
      jags_mod <- jags.model(mod_path,datastruct,inits=jinits,n.adapt=mcmc_params$nadapt) 
      update(jags_mod, n.iter=mcmc_params$nburnin)
      mod_samp <- coda.samples(jags_mod, monitorparams, n.iter=mcmc_params$nsamples, thin=mcmc_params$nthin)
      return(mod_samp)
    }
clusterExport(cl,c('mod_path','datastruct','mcmc_params','monitorparams','jinits'),envir=environment()) ## could just do 'JAGSmod','jags.model','coda.samples','load.module' here instead but:
clusterEvalQ(cl, {
      library(rjags)
      load.module('lecuyer')
      load.module('glm')
    }) #runs code in each blank cl instance of R
res <- parLapply(cl,1:mcmc_params$nchains,JAGSmod)
stopCluster(cl)
l_mcmc <- as.mcmc.list(lapply(res,as.mcmc))
parsum <- summary(window(l_mcmc))

Это можно легко обернуть в функцию, хотя может потребоваться передатьc(datastruct,mcmc_params,monitorparams).

Другие вопросы по тегам