如何提高备受诟病的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

相关文章
相关标签/搜索