缩短R for循环的计算时间

时间:2018-09-11 12:18:20

标签: r performance for-loop

尝试按具有4096列的数据帧(Camera1)中的行(690075)运行样条函数(每个列代表x轴上的位置),其中函数的输入变量是同一数据集的另一个数据集中的列使用for循环的长度(test $ vr);但我遇到了严重的计算时间问题。

我尝试将数据帧转换为矩阵并将输出存储在列表中,但无济于事。我必须对其他两个相同大小的数据帧(camera2,camera3)执行此操作。

代码

 # Note camera1 and test$vr are of the same length
 # Initialize
 final.data1 <- data.frame()

 #new wavelength range
 y1 <- round(seq(from = 4714 , to = 4900, length.out = 4096),3)

 system.time({
   for (i in 1:690075) {
       w1 = (as.numeric(colnames(camera1[-1]))) * (1.0 + test$vr[i]/299792.458)
       my.data1<-as.data.frame(t(splinefun(x = w1, y = camera1[i,][-1])(y1)))
       colnames(my.data1)=y1
       final.data1 <- bind_rows(final.data1, my.data1)
     } })

在具有344GB内存和30核心Intel(R)Xeon(R)CPU E5-2695 @ 2.30GHz的Ubuntu盒上运行

任何建议将不胜感激。 谢谢。

2 个答案:

答案 0 :(得分:3)

不看数据,优化代码并不容易,但我将从以下内容开始。

final.data1 <- matrix(nrow = 690075, ncol = 4096)

#new wavelength range
y1 <- round(seq(from = 4714 , to = 4900, length.out = 4096), 3)

system.time({
   w1 <- (as.numeric(colnames(camera1[-1]))) * (1.0 + test$vr/299792.458)
   for (i in 1:690075) {
       my.data1 <- t(splinefun(x = w1[i], y = camera1[i, ][-1])(y1))
       final.data1[i, ] <- my.data1
   }
})

final.data1 <- as.data.frame(final.data1)
colnames(final.data1) <- y1

说明:

  1. 我首先定义一个类matrix的对象来保存结果。我相信我对您的最终data.frame的理解正确。这样可以减少运行时间,因为

    • 矩阵比数据帧快得多,它们只是折叠的矢量,索引也很快。相反,数据框是可以容纳所有类型的数据,数字,字符,逻辑,其他列表等的列表,因此访问它们的成员很慢。

    • 通过在一个操作中保留结果的全部内存,可以节省R的内存管理例程的大量工作。要扩展final.data1遍历循环,非常耗时。

  2. w1是在循环外部使用R的矢量化性质计算的。此外,您重复了as.numeric(colnames(camera1[-1])) 690k次的计算!

测试这段代码,如果它不能产生相同的最终结果,只需说一遍,我就会看看是否可以做一些调试工作。

答案 1 :(得分:3)

首先删除所有只能执行一次的指令,然后将其置于for循环之外。例如:colnamesas.numeric

第二,尝试向量化。看来w1的计算可以向量化,因此只需删除[i]就可以在for循环外进行估算。

第三,将final.data1初始化为最终尺寸。对于添加到此data.frame的每一行,R将创建一个新的data.frame并增加一行,然后删除先前的data.frame。这将需要很长时间。因此,final.data1 <- matrix(NA, ncol=length(y1), nrow=NROW)

最后,如果要使用多个内核,请尝试用并行化的foreach loop替换for循环。所有行都可能是独立的:

require(foreach)
require(doSNOW)
cl <- makeCluster(25, type="FORK") # FORK not usable in Windows
registerDoSNOW(cl) # register the cluster
clusterExport(cl, c("objects", "needed", "by", "each", "iteration"), envir=environment()) # for example y1, w1 and camera1
final.data1<- foreach(i=icount(NROW), .combine=rbind, inorder=FALSE) %dopar%
{
  # your R code
}
stopCluster(cl)