【问题标题】:How could I speed up my R code? [closed]我怎样才能加快我的 R 代码? [关闭]
【发布时间】:2014-08-21 11:28:21
【问题描述】:

免责声明

大家好!我最近开始使用 R 进行编程。我的代码运行良好,但就速度而言,其中一些代码花费的时间太长而无法充分利用。我希望有人可以通过优化代码或使用其中一个多核包来帮助我使这段代码运行得更快。


关于代码

我有大型数据集,每个数据集包含大约 15000 个数字数据。该代码采用两个参数 (p, n),其中 p >= n,并生成数据的子集。它将 zyp.yuepilon 函数(来自 zyp 包)应用于子集的每一行。然后参数 n 用于在 n 大小的子集上应用相同的函数。

问题是我在嵌套的 for 循环中运行此代码:p 在 10:40 和 n 在 10:40,因此需要很长时间才能获得结果,而且它只是许多其他数据集中的一个。

sp <- function(p, n){
  library(zyp)

  data <- runif(15000, 1, 4)
  lower <- seq(80 - p + 1, by=1, length.out=length(data)-81)
  upper <- lower + p - 1

  subsets <- matrix(nrow=length(lower), ncol=p)
  for(j in 1:length(lower)){
    subsets[j, ] = data[lower[j] : upper[j]]
  }

  ret <- apply(subsets, 1, zyp.yuepilon)

  subset_n <- subsets[, 1:n]
  ret2 <- apply(subset_n, 1, zyp.yuepilon)
  return(list(ret, ret2))
}

基准测试结果以秒为单位:

expr      min       lq   median       uq      max neval
sp(7, 6) 92.77266 94.24901 94.53346 95.10363 95.64914    10

【问题讨论】:

  • 如果代码太慢,第一步是分析。见help("Rprof")
  • ^ 是的,你需要找出时间花在哪里以避免过早优化。
  • 但是,我怀疑zyp.yuepilon 是您的瓶颈。编写更快的实现或使用并行化。
  • 这个问题似乎离题了,因为它是关于优化工作代码的;它更适合 codereview.stackexchange.com。
  • 感谢 cmets,我非常感谢他们。我使用了 profiling,而 zyp.yuepilon 是 Roland 所写的瓶颈。我尝试使用降雪包,但并没有真正变得更快。确实是题外话,谢谢指出。以后会多加注意的。

标签: r performance loops nested-loops multicore


【解决方案1】:

这里是一系列的 cmets,而不是一个答案。

查看 zyp.yuepilon 函数体,通过在 R 会话中调用不带括号的函数,您会看到该函数和函数 zyp.sen 是用纯 R 代码(而不是编译代码)编写的。

最大的加速可能是通过使用Rcpp 包实现的,该包有助于在 R 中调用(编译)C++ 代码。事实上,这里有一个小的线性模型示例Fast LM model using Rcpp/RcppArmadillo

我倾向于使用 Rcpp 在 C++ 中重写 zyp.yuepilonzyp.sen 这两个函数,包括对子集向量的循环(您目前正在使用 apply 执行此操作)。

对于一般的 R 加速问题,请参阅此问题 R loop performance,以及 R 包 plyr,它可能为您采用 map-reduce 类型的方法来解决您的问题提供了一个入口点。

如果您想避开 C++,那么一系列微优化将是您最快的胜利。为了加快代码的apply 方面,您可以使用类似这样的东西

library(doParallel)
library(parallel)
library(foreach)
library(zyp)

cl<-makeCluster(4)
registerDoParallel(cl)

sp_1<-function(p=7, n=6){
N_ob=15000; 
off_set=81; 
N_ob_o=N_ob-off_set; 

am<-matrix(runif(N_ob*p),ncol=p); 
subsets<-am[-(1:off_set),];
ret=matrix(unlist( foreach(i=1:N_ob_o) %dopar% zyp::zyp.yuepilon(subsets[i,]),use.names=FALSE),ncol=11, byrow=TRUE);

subset_n <- subsets[, 1:n]
ret2=matrix(unlist( foreach(i=1:N_ob_o) %dopar% zyp::zyp.yuepilon(subset_n[i,]),use.names=FALSE),nrow=11);
return(list(ret, ret2))
}

sp<-function(p=7, n=6){

data <- runif(15000, 1, 4)
lower <- seq(80 - p + 1, by=1, length.out=length(data)-81)
upper <- lower + p - 1

subsets <- matrix(nrow=length(lower), ncol=p)
for(j in 1:length(lower)){
subsets[j, ] = data[lower[j] : upper[j]]
}

ret <- apply(subsets, 1, zyp.yuepilon)

subset_n <- subsets[, 1:n]
ret2 <- apply(subset_n, 1, zyp.yuepilon)
return(list(ret, ret2))
}

system.time(sp_1())
system.time(sp())

这使我的速度提高了大约 2 倍。但这取决于您的平台等。查看上述函数和包的帮助文件,并使用 makeCluster 调整集群数量到看看什么最适合您的平台(在没有关于您的特定设置的任何信息的情况下)。

另一种方法可能是通过library(compiler)使用字节码编译器来查看是否可以优化各种功能。

library(compiler)
enableJit(3);
zyp_comp<-cmpfun(zyp.yuepilon);

【讨论】:

    猜你喜欢
    • 2014-07-23
    • 1970-01-01
    • 2017-03-13
    • 2012-09-03
    • 2021-11-21
    • 1970-01-01
    • 1970-01-01
    • 2019-07-13
    • 2017-06-11
    相关资源
    最近更新 更多