Первое, что следует отметить, это то, что использование функции извлечения $
в пределах al oop делает это плохо. Было бы лучше: 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
, который будет l oop через каждый элемент переменных, представляющих интерес:
scen_sims[, glm := list(Map(fx_make_glm, n, rate1, n, rate2))]
К сожалению, это все еще не обеспечивает такую производительность, как идеальная: (
Unit: seconds
expr min lq mean median uq max neval
OP_loop 3.01 3.21 3.21 3.22 3.26 3.36 5
map_call 2.64 2.89 2.90 2.92 2.96 3.08 5
Мой параллельный пакет выбора future.apply
- просто поставьте future_
перед серией *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)))]