2013-04-12 8 views
12

Chciałbym przyśpieszyć moją funkcję bootstrap, która działa idealnie idealnie. Przeczytałem, że od R 2.14 jest pakiet o nazwie parallel, ale dla mnie jest to bardzo trudne. z niską znajomością informatyki, aby naprawdę ją wdrożyć. Może ktoś może pomóc.Używanie R równolegle do przyspieszenia bootstrap

Więc tutaj mamy bootstrap:

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=" ")) 
} 

Celem jest użycie przetwarzania równoległego/wykorzystać wiele rdzeni mojego komputera. Używam R pod Windows. Dzięki!

EDIT (po post przez Noego)

Poniższa składnia może być używany do testowania:

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) 

Jednak na moim komputerze prosty kod R jest szybsze. Czy jest to jeden ze znanych efektów ubocznych przetwarzania równoległego, tj. Powoduje, że koszty ogólne są rozwidleniem procesu, który zwiększa czas w "prostych zadaniach", takich jak ten?

Edytuj: Na moim komputerze kod parallel trwa około 5 razy dłużej niż kod "prosty". Ten czynnik najwyraźniej się nie zmienia, ponieważ zwiększam złożoność zadania (np. Zwiększam boot lub n). Więc może jest problem z kodem lub moim komputerem (przetwarzanie w systemie Windows?).

Odpowiedz

7

nie testowałem foreach z parallel backend w systemie Windows, ale wierzę, że to będzie pracować dla Ciebie:

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]) 
} 
+0

Dzięki, zsumowałem sugerowaną składnię do testowania (edytowany kod powyżej). Teraz używa 100% mojego procesora (tj. Wszystkich procesorów). Jest to jednak wolniejsze niż robienie tego bez przetwarzania równoległego, patrz wyżej. – tomka

+0

Byłoby świetnie, gdybyś mógł podać dodatkowe sugestie dotyczące problemu związanego z czasem, czyli dlaczego Twoja sugestia nie przyspiesza? Dzięki. – tomka

+0

Hmm. Ciekawy.Na moim komputerze (8 rdzeni HT, 8 GB pamięci RAM, Ubuntu 12.04) uzyskałem przyspieszenie około 3,4X przy małym wykorzystaniu pamięci RAM. Nie jestem zaznajomiony z wielowątkowością w środowisku Windows. Oto kilka rzeczy do wypróbowania: – Noah

8

Wypróbuj pakiet boot. Jest dobrze zoptymalizowany i zawiera argument parallel. Problem z tym pakietem polega na tym, że musisz napisać nowe funkcje do obliczania statystyk, które akceptują dane, nad którymi pracujesz, oraz wektor indeksów do ponownego próbkowania danych. Tak więc, począwszy od której zdefiniowanie data, można zrobić coś takiego:

# 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 jest wektorem o resampled statystyki i boot ma wiele przyjemnych sposobów łatwo robić rzeczy z nim - na przykład plot(b)

Należy pamiętać, że metody równoległe zależą od platformy. Na komputerze z systemem Windows musisz użyć parallel="snow".

+0

Twoje rozwiązanie przyspiesza o jakieś 25% na moim komputerze. To miłe. W prawdziwej aplikacji, na którą patrzę, problem jest znacznie bardziej złożony, ponieważ moja funkcja zwraca listę parametrów, które wszystkie muszą być bootstrapped. Dlatego szukam bezpośredniej implementacji równoległej. – tomka

+0

@tomka, 'boot' nadal działa dobrze w tej sytuacji. Funkcja, którą napiszesz, może zwrócić wektor parametrów, które Cię interesują. Rzeczywiście, jest to jedna z mocnych stron bootowania - możliwość samodzielnego zapisu dowolnej funkcji. –

3

Myślę, że głównym problemem jest to, że masz wiele małych zadań. W niektórych przypadkach można poprawić wydajność za pomocą zadanie wyrwy, co powoduje mniej, ale większych transmisję danych pomiędzy panem i pracowników, która jest często bardziej efektywne:

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]] 
    }) 
} 

lubię przy użyciu funkcji idiv do tego, ale możesz b=rep(boot/detectCores(),detectCores()), jeśli chcesz.