#r #parallel-processing
#r #параллельная обработка
Вопрос:
У меня есть медленная функция, которую я хочу применить к каждой строке в data.frame. Вычисления смущающе параллельны.
У меня 4 ядра, но встроенные функции R используют только одно.
Все, что я хочу сделать, это параллельный эквивалент:
data$c = slow.foo(data$a, data$b)
Я не могу найти четких инструкций о том, какую библиотеку использовать (перегружен выбором) и как ее использовать. Буду признателен за любую помощь.
Ответ №1:
parallel
Пакет включен в базовый R. Вот краткий пример использования parApply
из этого пакета:
library(parallel)
# Some dummy data
d <- data.frame(x1=runif(1000), x2=runif(1000))
# Create a cluster with 1 fewer cores than are available. Adjust as necessary
cl <- makeCluster(detectCores() - 1)
# Just like regular apply, but rows get sent to the various processes
out <- parApply(cl, d, 1, function(x) x[1] - x[2])
stopCluster(cl)
# Same as x1 - x2?
identical(out, d$x1 - d$x2)
# [1] TRUE
У вас также есть, например, parSapply
и parLapply
в вашем распоряжении.
Конечно, для примера, который я привел, векторизованная операция d$x1 - d$x2
выполняется намного быстрее. Подумайте, можно ли векторизовать ваши процессы, а не выполнять построчно.
Комментарии:
1. Спасибо за информацию. Ваш пример работает, но я не могу получить именованный эквивалент для работы. Я изменил
x[1]-x[2]
наx$x1-x$x2
. Это приводит к следующей ошибке:Error in checkForRemoteErrors(val) : 7 nodes produced errors; first error: $ operator is invalid for atomic vectors
2. @sharoz: Это потому, что строки упрощены до векторов (для которых
$
подмножество не является опцией). То же самое произойдет и для непараллельногоapply(d, 1, function(x) x$x1 - x$x2)
. Если вы хотите использовать имена, вы можете сделать:function(x) x['x1'] - x['x2']
.3. Еще раз спасибо, но это вызывает проблемы с именованными переменными. В исходном примере я определил
bar <- function(x) slow.foo(x['a'], x['b'])
. Затем я запустилparApply(cl, d, 1, bar)
который не может найти символ slow.foo (хотя он определен). Есть идеи?4. @sharoz: Помимо объекта, который вы передаете
parApply
(т.Е.d
), Вам необходимо отправлять объекты / функции в кластерные процессыclusterExport
. Попробуйте:clusterExport(cl, 'slow.foo')
доparApply
. Этот символьный вектор должен также включать имена любых объектов, на которые ссылаются в телеslow.foo
(кроме тех, которые передаются изbar
). Имейте в виду, что если какой-либо из указанных объектов огромен, вы можете столкнуться с проблемами с памятью, отправив копии всем процессам.