У меня много строк, и в каждой строке я вычисляю одночлен нелинейной функции. У меня четырехъядерная машина Ubuntu, которая не перестает выполнять мой код уже два дня. Неудивительно, что я ищу способы ускорить работу ;-)
После некоторого исследования я заметил, что в настоящее время используется только одно ядро, а распараллеливание - это то, что нужно. Копая глубже, я пришел к выводу (возможно, ошибочному?), что пакет foreach
не очень подходит для моей задачи, потому что получается слишком много накладных расходов (см., например, SO). Хорошей альтернативой представляется multicore
для Unix-машин. В частности, функция pvec
кажется наиболее эффективной после того, как я проверил страницу помощи.
Однако, если я правильно понимаю, эта функция принимает только один вектор и разбивает его соответствующим образом. Мне нужна функция, которая может быть распараллелена, но принимает несколько векторов (или data.frame
вместо этого), как это делает функция mapply
. Может быть, я что-то упустил?
Вот небольшой пример того, что я хочу сделать: (Обратите внимание, что я включил сюда пример plyr
, потому что он может быть альтернативой базовой функции mapply
и имеет опцию параллелизации. Однако в моей реализации она работает медленнее, а внутри она вызывает foreach
для распараллеливания, поэтому я думаю, что это не поможет. Правильно ли это?)
library(plyr)
library(foreach)
n <- 10000
df <- data.frame(P = rnorm(n, mean=100, sd=10),
B0 = rnorm(n, mean=40, sd=5),
CF1 = rnorm(n, mean=30, sd=10),
CF2 = rnorm(n, mean=30, sd=5),
CF3 = rnorm(n, mean=90, sd=8))
get_uniroot <- function(P, B0, CF1, CF2, CF3) {
uniroot(function(x) {-P + B0 + CF1/x + CF2/x^2 + CF3/x^3},
lower = 1,
upper = 10,
tol = 0.00001)$root
}
system.time(x1 <- mapply(get_uniroot, df$P, df$B0, df$CF1, df$CF2, df$CF3))
#user system elapsed
#0.91 0.00 0.90
system.time(x2 <- mdply(df, get_uniroot))
#user system elapsed
#5.85 0.00 5.85
system.time(x3 <- foreach(P=df$P, B0=df$B0, CF1=df$CF1, CF2=df$CF2, CF3=df$CF3, .combine = "c") %do% {
get_uniroot(P, B0, CF1, CF2, CF3)})
#user system elapsed
# 10.30 0.00 10.36
all.equal(x1, x2$V1) #TRUE
all.equal(x1, x3) #TRUE
Также я попытался реализовать функцию Райана Томпсона chunkapply из ссылки SO выше (только избавился от части doMC
, потому что не смог ее установить. Однако его пример работает, даже после корректировки его функции),
но не смог заставить ее работать. Однако, поскольку он использует foreach
, я подумал, что к нему применимы те же аргументы, о которых говорилось выше, поэтому не стал долго пытаться.
#chunkapply(get_uniroot, list(P=df$P, B0=df$B0, CF1=df$CF1, CF2=df$CF2, CF3=df$CF3))
#Error in { : task 1 failed - "invalid function value in 'zeroin'"
PS: Я знаю, что мог бы просто увеличить tol
, чтобы уменьшить количество шагов, необходимых для нахождения унироты. Однако я уже установил tol
как можно больше.