У меня много строк и на каждой строке я вычисляю uniroot нелинейной функции. У меня есть четырехъядерный компьютер Ubuntu, который не прекратил работу моего кода в течение двух дней. Неудивительно, что я ищу способы ускорить работу ;-)Есть ли эффективный способ распараллеливать mapply?
После некоторых исследований я заметил, что в настоящее время используется только одно ядро, и распараллеливание - это то, что нужно сделать. Копая глубже, я пришел к выводу (может быть, неправильно?), Что пакет 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
, потому что я не смог установить его. Его пример работает даже после настройки его функции.), , но didn не получится. Однако, поскольку он использует 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
сократить количество шагов, которые необходимо найти uniroot. Тем не менее, я уже установил tol
как можно больше.
Благодарим за прекрасное объяснение и пример. Это то, что я искал. Кроме того, я не знал, что «parallel» был доступен с R2.14.0, это хорошо знать. –
Добро пожаловать. Параллельно все еще нужно загружать, прежде чем вы сможете использовать его, конечно, но он поставляется со стандартной установкой. –