2013-04-12 41 views
12

Tôi muốn tăng tốc độ chức năng khởi động, hoạt động hoàn toàn tốt. Tôi đọc rằng kể từ R 2.14 có một gói gọi là parallel, nhưng tôi thấy nó rất khó cho sb. với kiến ​​thức khoa học máy tính thấp để thực sự triển khai nó. Có lẽ ai đó có thể giúp đỡ.Sử dụng R song song để tăng tốc độ bootstrap

Vì vậy, ở đây chúng tôi có một 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=" ")) 
} 

Mục đích là để sử dụng song song chế biến/khai thác đa lõi của máy tính của tôi. Tôi đang chạy R dưới Windows. Cảm ơn!

EDIT (sau khi trả lời bởi Noah)

Cú pháp sau đây có thể được sử dụng để thử nghiệm:

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) 

Tuy nhiên, trên máy tính của tôi mã R đơn giản là nhanh hơn. Đây có phải là một trong những tác dụng phụ đã biết của việc xử lý song song, tức là nó gây ra chi phí cho việc chia nhỏ quá trình thêm vào thời gian trong 'các nhiệm vụ đơn giản' như thế này?

Chỉnh sửa: Trên máy của tôi, mã parallel mất khoảng 5 lần dài hơn mã 'đơn giản'. Yếu tố này dường như không thay đổi khi tôi tăng độ phức tạp của tác vụ (ví dụ: tăng boot hoặc n). Vì vậy, có thể có một vấn đề với mã hoặc máy của tôi (Windows dựa trên chế biến?).

Trả lời

7

tôi đã không kiểm tra foreach với parallel backend trên Windows, nhưng tôi tin rằng điều này sẽ làm việc cho bạn:

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

Cảm ơn, tôi đã tổng hợp cú pháp được đề xuất để kiểm tra (mã đã chỉnh sửa ở trên). Nó hiện sử dụng 100% CPU của tôi (tức là tất cả các bộ vi xử lý). Tuy nhiên, điều này là chậm hơn so với thực hiện nó mà không cần xử lý song song, xem ở trên. – tomka

+0

Sẽ tuyệt vời nếu bạn có thể đưa ra bất kỳ đề xuất bổ sung nào về vấn đề thời gian, tức là tại sao đề xuất của bạn không tăng tốc nó? Cảm ơn. – tomka

+0

Hmm. Hấp dẫn.Trên máy tính của tôi, (8 lõi HT, 8 GB ram, Ubuntu 12.04), tôi có tốc độ khoảng 3.4X với ít sử dụng RAM. Tôi không phải là quen thuộc với đa luồng trong một môi trường cửa sổ. Dưới đây là một số điều cần thử: – Noah

8

Thử gói boot. Nó được tối ưu hóa tốt và chứa đối số parallel. Điều khó khăn với gói này là bạn phải viết các hàm mới để tính toán thống kê của bạn, chấp nhận dữ liệu bạn đang làm việc và một vectơ các chỉ mục để lấy lại dữ liệu. Vì vậy, bắt đầu từ nơi bạn xác định data, bạn có thể làm một cái gì đó như thế này:

# 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 là một vector của các số liệu thống kê resampled, và boot có rất nhiều phương pháp tốt đẹp để dễ dàng làm mọi thứ với nó - ví dụ plot(b)

Lưu ý rằng các phương pháp song song phụ thuộc vào nền tảng của bạn. Trên máy tính Windows, bạn cần sử dụng parallel="snow".

+0

Giải pháp của bạn đang tăng tốc bằng 25% trên máy tính của tôi. Thật tuyệt. Trong ứng dụng thực tế tôi đang xem xét, vấn đề phức tạp hơn nhiều, bởi vì hàm của tôi trả về một danh sách các tham số, tất cả đều phải được khởi động. Vì vậy, tôi đang tìm kiếm một thực hiện trực tiếp song song. – tomka

+0

@tomka, 'boot' vẫn hoạt động tốt trong tình huống này. Hàm bạn viết có thể trả về một vectơ các tham số mà bạn quan tâm. Thật vậy, đây là một trong những điểm mạnh của khởi động - khả năng tự viết bất kỳ hàm nào tùy ý. –

3

Tôi nghĩ rằng vấn đề chính là bạn có rất nhiều nhiệm vụ nhỏ. Trong một số trường hợp, bạn có thể cải thiện hiệu suất của bạn bằng cách sử dụng nhiệm vụ chunking, mà kết quả trong ít, nhưng nếu truyền dữ liệu lớn hơn giữa chủ và người lao động, mà thường là hiệu quả hơn:

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

Tôi thích sử dụng các idiv chức năng cho điều này, nhưng bạn có thể b=rep(boot/detectCores(),detectCores()) nếu bạn muốn.

Các vấn đề liên quan