dopar内代码的过程优化

dopar内代码的过程优化,r,foreach,data.table,doparallel,R,Foreach,Data.table,Doparallel,我正在尝试优化我的代码以多次运行glms,我想利用并行化,或者使用foreach或者其他更有效的方法 如你所见;for循环运行270000 glms大约需要800秒;而foreach和dopar一起使用时,它会不自觉地持续使用(它会崩溃,或者我会在几个小时后强制停止) 谢谢你的帮助 吉内什 library(data.table) library(parallel) library(doParallel) library(foreach) scen_bin <- expand.grid(n

我正在尝试优化我的代码以多次运行glms,我想利用并行化,或者使用
foreach
或者其他更有效的方法

如你所见;
for
循环运行270000 glms大约需要800秒;而
foreach
dopar
一起使用时,它会不自觉地持续使用(它会崩溃,或者我会在几个小时后强制停止)

谢谢你的帮助

吉内什

library(data.table)
library(parallel)
library(doParallel)
library(foreach)
scen_bin <- expand.grid(n = c(10, 20, 30), rate1 = c(0.1, 0.2, 0.3),
  rate2 = c(0.5, 0.6, 0.9))

rep <- 10000
scen_sims <- rbindlist(replicate(rep, scen_bin, simplify = FALSE),
  idcol = TRUE)
scen_sims[, `:=`(glm, list(c(1L, 2L)))]

for (i in 1:270000) {
  set(scen_sims, i, 8L, list(glm(formula = c(rbinom(scen_sims$drug[i], 1L, scen_sims$Treatment_Rates[i]),
    rbinom(scen_sims$control[i], 1L, scen_sims$Comparator_Rates[i])) ~ factor(c(rep("Trt",
    scen_sims$drug[i]), rep("Cont", scen_sims$control[i]))), family = "binomial")))
}

split_scen_sims <- split(scen_sims, seq(1, 270000, length.out = 1000))


jh <- foreach(x = 1:1000, .packages = c("data.table")) %dopar% {
  jh <- split_scen_sims[[x]]
  for (i in 1:270000) {
    set(jh, i, 8L, list(glm(formula = c(rbinom(jh$n[i], 1L, jh$rate1[i]), rbinom(jh$n[i],
      1L, jh$rate1[i])) ~ factor(c(rep("Trt", jh$n[i]), rep("Cont", jh$n[i]))),
      family = "binomial")))
  }
  return(jh)
}
库(data.table)
图书馆(平行)
图书馆(双平行)
图书馆(foreach)

scen_bin首先要注意的是,在循环中使用提取函数
$
会使其性能不佳。最好是1)生成一个函数,然后2)使用常规的
data.table
调用

fx_make_glm = function(drug, treat_rate, control, Comparator_Rates){
  glm(formula = c(rbinom(drug, 1L, treat_rate),
                  rbinom(control, 1L, Comparator_Rates)) ~
        factor(c(rep("Trt", drug), rep("Cont", control))), 
      family = "binomial")
}
这将大大简化其余部分-我将使用
Map
,它将循环遍历感兴趣的变量的每个元素:

scen_sims[, glm := list(Map(fx_make_glm, n, rate1, n, rate2))]
不幸的是,这仍然没有提供理想的性能:(

我选择的并行程序包是
future.apply
-只需将
future\uu
放在您的
*apply
系列前面,您就可以进行并行评估:

library(future.apply)
plan(multiprocess)
system.time({
  scen_sims[, glm := list(future_Map(fx_make_glm, n, rate1, n, rate2))]
})

   user  system elapsed 
   1.22    0.13    3.22 

## truncated the microbenchmark call

Unit: seconds
            expr  min   lq mean median   uq  max neval
         OP_loop 2.93 2.98 3.08   3.00 3.18 3.32     5
        map_call 2.65 2.70 2.94   2.89 3.18 3.25     5
 future_map_call 2.84 3.24 3.37   3.43 3.49 3.85     5
我在Windows上,有2个内核/4个线程。如果我在Linux上,我会尝试
plan(multicore)
,看看分叉进程是否更有效率

数据生成:

library(data.table)
## generate data
scen_bin <- expand.grid(n = c(10, 20, 30), rate1 = c(0.1, 0.2, 0.3),
                        rate2 = c(0.5, 0.6, 0.9))

rep <- 50L
scen_sims <- rbindlist(replicate(rep, scen_bin, simplify = FALSE),
                       idcol = TRUE)
scen_sims[, `:=`(glm, list(c(1L, 2L)))]
库(data.table)
##生成数据

scen_bin最简单的例子真的需要800秒才能运行吗?@Cole这是我能得到的最接近的例子;但我愿意接受关于如何优化它的建议!:)你能让它重现吗?
glm
中使用的列都不存在从并行会话在主会话中重写值通常是个坏主意,会导致意外行为。更好的解决方案是并行创建每个模型,在列表中返回它们,并将该列表添加为新列(如果需要)。谢谢您指出这一点,嗯。。谢谢我使用set是因为我看到它非常有效。我仍然不明白为什么多核并行会导致性能降低。我很想知道,并行化这段代码的最快方法。如果运行100个glms需要6秒,我希望使用100个内核,我应该能够在不到10秒的时间内运行10000个。。谢谢我使用set是因为我看到它非常有效。我仍然不明白为什么多核并行会导致性能降低。我很想知道,并行化这段代码的最快方法。如果运行100个glms需要6秒,我希望使用100个内核,我应该能够在10秒内运行10000个?我也在Windows上。我觉得如果我在linux上,这会更有成效。你试过代码了吗?关于
设置
,您可以很好地使用该部件。是
DF$var[i]
扼杀了性能。参见编辑-我制作了一个更好的
data.table
方法。
library(data.table)
## generate data
scen_bin <- expand.grid(n = c(10, 20, 30), rate1 = c(0.1, 0.2, 0.3),
                        rate2 = c(0.5, 0.6, 0.9))

rep <- 50L
scen_sims <- rbindlist(replicate(rep, scen_bin, simplify = FALSE),
                       idcol = TRUE)
scen_sims[, `:=`(glm, list(c(1L, 2L)))]