如何提高備受詬病的R的運行速度

說到R,人們除了讚美它漂亮簡潔的做圖功能外,就是抱怨它的運行速度問題。做爲常規使用,好比數據整理分析,統計計算或者做圖等,或許沒有感受到它的運行速度有問題。可是若是數據量很大,像基因組數據,那麼運行起來就尤爲慢了。特別是對於循環語句,猶如老牛拉破車,因此在數據量很大的狀況下,儘可能不要在R中使用循環語句。html

那麼循環語句在R中會慢到什麼地步?咱們經過R語言和C語言的比較就能看出一些端倪。編程

咱們假設有這麼兩個數據框,以下圖。咱們要判斷每個pos中的數據(4,15,19,27)是否落在第一個數據框的數據區間內(2-5,7-11,17-20,23-28,32-39)。這樣咱們就會用到兩個嵌套for循環,對第二個數據框中的每個數,依次比對第一個數據框中的每個數據段。app

如何提高備受詬病的R的運行速度

首先咱們使用隨機數生成這麼兩個模擬數據框編程語言

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循環,大概運行來:函數

如何提高備受詬病的R的運行速度
下面咱們看一看在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的運行速度
能夠看出,一樣的一段代碼,獲得相同的結果,在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

相關文章
相關標籤/搜索