改进for循环(R)中的执行时间

改进for循环(R)中的执行时间,r,for-loop,iteration,output,lapply,R,For Loop,Iteration,Output,Lapply,这是一个可复制的for循环示例。因为我想做3000次迭代,而我的矩阵比这个可复制的例子要大得多,所以计算机会崩溃。我该怎么做呢 我曾读到,R中没有循环,相反,web建议使用向量和应用函数,但我无法用这些函数构建公式 矩阵: row.names <- c('A2003','B2010','C2011','D2010','E2001','F2005','F2009','G2003','G2007','H2004','H2010') sp1 <- c(4,83,1,2,4,3,1,5,7,

这是一个可复制的for循环示例。因为我想做3000次迭代,而我的矩阵比这个可复制的例子要大得多,所以计算机会崩溃。我该怎么做呢

我曾读到,R中没有循环,相反,web建议使用向量和应用函数,但我无法用这些函数构建公式

矩阵:

row.names <- c('A2003','B2010','C2011','D2010','E2001','F2005','F2009','G2003','G2007','H2004','H2010')
sp1 <- c(4,83,1,2,4,3,1,5,7,2,4)
sp2 <- c(5,0,2,3,10,5,0,2,4,3,1)
sp3 <- c(7,2,4,8,7,2,4,83,1,5,7)
sp4 <- c(0,2,4,2,4,12,1,5,7,2,4)
Site <- c('A','B','C','D','E','F','F','G','G','H','H')
Year <- c('2003','2010','2011','2010','2001','2005','2009','2003','2007','2004','2010')
Obs <- c(1,1,1,4,9,6,8,2,5,2,3)
ID <- c('A2003','B2010','C2011','D2010','E2001','F2005','F2009','G2003','G2007','H2004','H2010')
df<- data.frame(row.names, sp1, sp2, sp3, sp4, Site, Year, Obs, ID)
rownames(df) <- df[,1]
df[,1] <- NULL
df
df.1 <- subset(df, Obs == 1)
df.more <- subset(df, Obs >= 2)
df.1
df.more

row.names我不熟悉
vegan
套餐,我能给你的建议有点有限。在大多数情况下,您已经为
循环构建了
,正如您在下面所看到的,通过将其转换为函数并通过
lappy
运行它,您不会获得太多收益

我认为最好的办法是并行化代码。在下面的示例中,如果将
for
循环转换为函数并使用
parlappy
,如果包含集群构建时间,则可以节省几秒钟。如果不考虑集群构建时间,在我的7核上大约快5倍。计算时间的变化将因您可以运行的内核数量而异。但我认为这可能是你目前最好的选择

library(parallel)
library(vegan) 

row.names <- c('A2003','B2010','C2011','D2010','E2001','F2005','F2009','G2003','G2007','H2004','H2010')
sp1 <- c(4,83,1,2,4,3,1,5,7,2,4)
sp2 <- c(5,0,2,3,10,5,0,2,4,3,1)
sp3 <- c(7,2,4,8,7,2,4,83,1,5,7)
sp4 <- c(0,2,4,2,4,12,1,5,7,2,4)
Site <- c('A','B','C','D','E','F','F','G','G','H','H')
Year <- c('2003','2010','2011','2010','2001','2005','2009','2003','2007','2004','2010')
Obs <- c(1,1,1,4,9,6,8,2,5,2,3)
ID <- c('A2003','B2010','C2011','D2010','E2001','F2005','F2009','G2003','G2007','H2004','H2010')
df<- data.frame(row.names, sp1, sp2, sp3, sp4, Site, Year, Obs, ID)
rownames(df) <- df[,1]
df[,1] <- NULL
df
df.1 <- subset(df, Obs == 1)
df.more <- subset(df, Obs >= 2)
df.1
df.more

more.fun <- function(df.more, df.1)
{
  rnd.more <- do.call(rbind, lapply(split(df.more, df.more$Site),
                                      function(df.more) df.more[sample(nrow(df.more), 1,replace=FALSE) , ])
  )
  rnd.df <- rbind(df.1,rnd.more)                                   
  rnd.df.bc <- as.matrix(vegdist(rnd.df[1:4], method="bray"))  
  rnd.df.bc[lower.tri(rnd.df.bc,diag=TRUE)] <- NA
  triang <- rnd.df.bc[!is.na(rnd.df.bc)]
  mean.bc <- mean(triang)
  list(rnd = rnd.df, bc = rnd.df.bc, ave = mean.bc)
}

start.orig <- Sys.time() 
  set.seed(pi)
    iterations <- 3000
    out <- vector("list", iterations)
    for(i in 1:iterations){      
      rnd.more <- do.call(rbind, lapply(split(df.more, df.more$Site),
                            function(df.more) df.more[sample(nrow(df.more), 1,replace=FALSE) , ])
        )
      rnd.df <- rbind(df.1,rnd.more)                                   
      rnd.df.bc <- as.matrix(vegdist(rnd.df[1:4], method="bray"))  
      rnd.df.bc[lower.tri(rnd.df.bc,diag=TRUE)] <- NA
      triang <- rnd.df.bc[!is.na(rnd.df.bc)]
      mean.bc <- mean(triang)
      out[[i]] <- list(rnd = rnd.df, bc = rnd.df.bc, ave = mean.bc)
  }
end.orig <- Sys.time()

start.apply <- Sys.time()
  fn = out <- lapply(1:3000, function(i) more.fun(df.more, df.1))
end.apply <- Sys.time()


start.parallel <- Sys.time()
  cl <- makeCluster(7)
  clusterEvalQ(cl, library(vegan))
  clusterExport(cl, c("df.more", "df.1", "more.fun"))
start.parallel.apply <- Sys.time()
  out <- parLapply(cl, 1:3000, function(i) more.fun(df.more, df.1))
end.parallel <- Sys.time()


#* Compare times
end.orig - start.orig
end.apply - start.apply
end.parallel - start.parallel
end.parallel - start.parallel.apply
库(并行)
图书馆(素食主义者)

row.names预计算样本索引:

idx <- lapply(1:iterations, function(x) {
  tapply(1:nrow(df.more), as.character(df.more$Site), function(y) {
    if(length(y) == 1) y else sample(y, 1)
  })
})

idx <- lapply(idx, function(ids) c(1:nrow(df.1), ids + nrow(df.1)))
现在,您只需索引预计算的对象,而无需在每个循环中计算它们:

iterations <- 3000
out <- vector("list", iterations)
for(i in 1:iterations){      
  rnd.df.bc <- as.matrix(vegdist(rnd.df[idx[[i]] ,1:4], method="bray"))  
  rnd.df.bc[lower.tri(rnd.df.bc,diag=TRUE)] <- NA
  triang <- rnd.df.bc[!is.na(rnd.df.bc)]
  mean.bc <- mean(triang)
  out[[i]] <- list(rnd = rnd.df, bc = rnd.df.bc, ave = mean.bc)
}
使之平行:
cl备注:R允许将函数名指定为字符串,但这是类型系统颠覆的废话,不要这样做;直接使用函数名。在你的例子中,这意味着:写“
[[
`而不是
”[[”
。素食主义者来自哪里?@A.Idigoras,请注意,如果你没有包含所有必要的软件包,那么你的例子就不能真正再现。
vegdist
来自于
vegan
软件包。一旦我弄明白了这一点,这个例子运行得很好。嗨@Heroka,我正在使用素食主义者(method=“bray”)来自vegan软件包,因为我想基于物种创建一个相似矩阵(1到4列)对于每次迭代。您可以将大量操作移出迭代循环。例如,当您可以创建一个采样索引列表并在循环中引用该列表时,为什么每次都要在循环中采样。与
rbind
s相同。您可以创建一个主
data.frame
并将预采样索引传递给它es.Hi@Benjamin,我正在尝试使用我的数据执行此操作。在脚本运行时,我想问您一个有关群集的问题。您为什么选择7个内核?当我执行此操作时,我收到以下错误:checkForRemoteErrors(val)中的错误:7个节点产生错误;第一个错误:组长度为0,但数据长度>0我的计算机上有8个核。我经常使用7个核来保留一个核,以便在等待时处理其他事务(电子邮件等)。您必须检查您的机器上有多少个内核。因此,这运行得很好,@Zelazny7。谢谢!现在我发现函数捕获(脚本的最后一部分)也存在另一个问题…此时计算机再次崩溃。还有什么想法吗?我会尝试使用
sink
。这可能还需要一段时间,但我通常会将10万行转换后的模型代码写入一个文件:
sink(“test.txt”);lappy(out,`[`,“rnd”);sink()
idx <- lapply(1:iterations, function(x) {
  tapply(1:nrow(df.more), as.character(df.more$Site), function(y) {
    if(length(y) == 1) y else sample(y, 1)
  })
})

idx <- lapply(idx, function(ids) c(1:nrow(df.1), ids + nrow(df.1)))
rnd.df <- rbind(df.1, df.more)
iterations <- 3000
out <- vector("list", iterations)
for(i in 1:iterations){      
  rnd.df.bc <- as.matrix(vegdist(rnd.df[idx[[i]] ,1:4], method="bray"))  
  rnd.df.bc[lower.tri(rnd.df.bc,diag=TRUE)] <- NA
  triang <- rnd.df.bc[!is.na(rnd.df.bc)]
  mean.bc <- mean(triang)
  out[[i]] <- list(rnd = rnd.df, bc = rnd.df.bc, ave = mean.bc)
}
f1 = my method
f2 = OPs code

> microbenchmark(f1(), f2(), times=5L)
Unit: seconds
 expr      min        lq      mean   median        uq       max neval
 f1()  2.21069  4.877017  4.666875  5.27416  5.444411  5.528096     5
 f2() 13.54813 13.554965 19.500247 14.51089 27.074520 28.812732     5
cl <- makeCluster(3)
registerDoSNOW(cl)

out <- foreach(i = 1:iterations, .packages=c('vegan')) %do%
{
  rnd.df.bc <- as.matrix(vegdist(rnd.df[idx[[i]] ,1:4], method="bray"))  
  rnd.df.bc[lower.tri(rnd.df.bc,diag=TRUE)] <- NA
  triang <- rnd.df.bc[!is.na(rnd.df.bc)]
  mean.bc <- mean(triang)
  list(rnd = rnd.df, bc = rnd.df.bc, ave = mean.bc)
}

stopCluster(cl)