Использование R параллельно для ускорения загрузки

Я бы хотел ускорить мою функцию загрузки, которая отлично работает сама по себе. Я читал, что, поскольку R 2.14 есть пакет под названием parallel, но мне очень сложно найти sb. с низким уровнем знаний в области информатики, чтобы реально реализовать его. Может быть, кто-то может помочь.

Итак, у нас есть бутстрап:

n<-1000
boot<-1000
x<-rnorm(n,0,1)
y<-rnorm(n,1+2*x,2)
data<-data.frame(x,y)
boot_b<-numeric()
for(i in 1:boot){
  bootstrap_data<-data[sample(nrow(data),nrow(data),replace=T),]
  boot_b[i]<-lm(y~x,bootstrap_data)$coef[2]
  print(paste('Run',i,sep=" "))
}

Цель состоит в том, чтобы использовать параллельную обработку/использование нескольких ядер моего ПК. Я запускаю R под Windows. Спасибо!

EDIT (после ответа Ноя)

Для тестирования можно использовать следующий синтаксис:

library(foreach)
library(parallel)
library(doParallel)
registerDoParallel(cores=detectCores(all.tests=TRUE))
n<-1000
boot<-1000
x<-rnorm(n,0,1)
y<-rnorm(n,1+2*x,2)
data<-data.frame(x,y)
start1<-Sys.time()
boot_b <- foreach(i=1:boot, .combine=c) %dopar% {
  bootstrap_data<-data[sample(nrow(data),nrow(data),replace=T),]
  unname(lm(y~x,bootstrap_data)$coef[2])
}
end1<-Sys.time()
boot_b<-numeric()
start2<-Sys.time()
for(i in 1:boot){
  bootstrap_data<-data[sample(nrow(data),nrow(data),replace=T),]
  boot_b[i]<-lm(y~x,bootstrap_data)$coef[2]
}
end2<-Sys.time()
start1-end1
start2-end2
as.numeric(start1-end1)/as.numeric(start2-end2)

Однако на моей машине простой R-код быстрее. Является ли это одним из известных побочных эффектов параллельной обработки, т.е. Вызывает накладные расходы, чтобы развить процесс, который добавляет к времени в "простых задачах", как этот?

Изменить: на моей машине код parallel занимает примерно в 5 раз дольше, чем "простой" код. Этот фактор, по-видимому, не изменяется, поскольку я увеличиваю сложность задачи (например, увеличиваю boot или n). Так что, возможно, есть проблема с кодом или моей машиной (обработка на базе Windows?).

Ответ 1

Попробуйте пакет boot. Он хорошо оптимизирован и содержит аргумент parallel. Трудная вещь с этим пакетом заключается в том, что вам нужно написать новые функции для расчета вашей статистики, которые принимают данные, над которыми вы работаете, и вектор индексов для повторной выборки данных. Итак, начиная с того, где вы определяете data, вы можете сделать что-то вроде этого:

# Define a function to resample the data set from a vector of indices
# and return the slope
slopeFun <- function(df, i) {
  #df must be a data frame.
  #i is the vector of row indices that boot will pass
  xResamp <- df[i, ]
  slope <- lm(y ~ x, data=xResamp)$coef[2] 
} 

# Then carry out the resampling
b <- boot(data, slopeFun, R=1000, parallel="multicore")

b$t - это вектор измененной статистики, а boot имеет множество хороших методов, которые легко могут сделать с ним - например plot(b)

Обратите внимание, что параллельные методы зависят от вашей платформы. На вашей машине с Windows вам нужно использовать parallel="snow".

Ответ 2

Я не тестировал foreach с бэкэндом parallel в Windows, но я считаю, что это сработает для вас:

library(foreach)
library(doSNOW)

cl <- makeCluster(c("localhost","localhost"), type = "SOCK")
registerDoSNOW(cl=cl)

n<-1000
boot<-1000
x<-rnorm(n,0,1)
y<-rnorm(n,1+2*x,2)
data<-data.frame(x,y)
boot_b <- foreach(i=1:boot, .combine=c) %dopar% {
  bootstrap_data<-data[sample(nrow(data),nrow(data),replace=T),]
  unname(lm(y~x,bootstrap_data)$coef[2])
}

Ответ 3

Я думаю, главная проблема заключается в том, что у вас много мелких задач. В некоторых случаях вы можете повысить свою производительность за счет использования чередования задач, что приводит к меньшему объему и большей передаче данных между мастером и работниками, что часто бывает более эффективным:

boot_b <- foreach(b=idiv(boot, chunks=getDoParWorkers()), .combine='c') %dopar% {
  sapply(1:b, function(i) {
    bdata <- data[sample(nrow(data), nrow(data), replace=T),]
    lm(y~x, bdata)$coef[[2]]
  })
}

Мне нравится использовать функцию idiv для этого, но вы можете b=rep(boot/detectCores(),detectCores()), если хотите.