說到R,人們除了讚美它漂亮簡潔的做圖功能外,就是抱怨它的運行速度問題。做爲常規使用,好比數據整理分析,統計計算或者做圖等,或許沒有感受到它的運行速度有問題。可是若是數據量很大,像基因組數據,那麼運行起來就尤爲慢了。特別是對於循環語句,猶如老牛拉破車,因此在數據量很大的狀況下,儘可能不要在R中使用循環語句。html
那麼循環語句在R中會慢到什麼地步?咱們經過R語言和C語言的比較就能看出一些端倪。編程
咱們假設有這麼兩個數據框,以下圖。咱們要判斷每個pos中的數據(4,15,19,27)是否落在第一個數據框的數據區間內(2-5,7-11,17-20,23-28,32-39)。這樣咱們就會用到兩個嵌套for循環,對第二個數據框中的每個數,依次比對第一個數據框中的每個數據段。app
首先咱們使用隨機數生成這麼兩個模擬數據框編程語言
set.seed(111) creat_test <- function(len, seg){ x <- sample(1:len,2*seg, replace = F) x <- x[order(x)] start = numeric() end = numeric() for (i in seq(1,length(x),2)){ start <- c(start,x[i]) end <- c(end,x[i+1]) } test_df <- data.frame("start" = start, "end" = end) return(test_df) } # create first data frame, using length = 7,000,000, segments = 20,000 test_data <- creat_test(7000000, 200000) #object.size(test_data) -- 3.2Mb # create second data frame, sequence data sequence <- data.frame('x' = sample(1:7000000, 400, replace = F)) sequence$x <- sequence[order(sequence$x),]
自此,咱們有了兩個測試數據框,第一個test_data裏面有20萬條觀測,第二個sequence裏面有400個觀測,那麼咱們首先經過R中的for循環來判斷這400個觀測時候落在來第一個數據框中數據段內。ide
# using R loop to see if sequence in test_data range R_time <- function(sequence, test_data){ num_in <- 0 for (i in 1:nrow(sequence)){ for (j in 1:nrow(test_data)){ if (sequence[i,1] > test_data[j,1] & sequence[i,1] < test_data[j,2]){ num_in <- num_in + 1 break } } } print(num_in) } system.time(R_time(sequence,test_data))
這段代碼中兩個for循環,大概運行來:函數
下面咱們看一看在C語言中完成這段代碼須要多長時間。本人並不瞭解C語言,可是Rcpp包提供了在R中寫C代碼的可能,因此使用Rcpp完成上述功能以下:oop
# using Rcpp library(Rcpp) cppFunction(' int Rcpp_time(DataFrame sequence, DataFrame test_data){ IntegerVector start=test_data["start"]; IntegerVector end=test_data["end"]; IntegerVector pos=sequence["x"]; int seq_size=sequence.nrow(); int test_size=test_data.nrow(); int num_in=0; for(int i=0; i<=seq_size; i++){ for(int j=0; j<=test_size; j++){ if(pos[i]>start[j] && pos[i]<end[j]){ num_in++; break; } } } return num_in; } ') system.time(Rcpp_time(sequence,test_data))
而這段代碼的運行時間僅僅爲:測試
能夠看出,一樣的一段代碼,獲得相同的結果,在R中運行的時間是在C中運行時間的數萬倍!什麼概念:code
在R中你要等1個多小時,在C中你在1秒內就完成!orm
固然這也很好理解,畢竟相對於C來說,R屬於高級編程語言,並且是解釋型語言,沒有C的編譯過程,因此R會針對每個for循環一一執行,這也下降了速度。
那麼問題來了,應該怎樣提升R的運行速度呢?
一、避免使用for循環,尤爲是數據量特別大的時候;
二、避免數據的複製,使用%>%之類的管道操做;
三、使用一些更快的R包處理數據,好比data.table;
四、使用apply、lapply等之類的函數代替for;
五、使用Rcpp編寫C語言函數;
六、使用多核並行計算(能夠經過lapply來實現);
能夠參考http://adv-r.had.co.nz/Performance.html