使用嵌入式 lapply 循环优化 foreach - 是否可以优化代码?

问题描述

我有以下代码块,它们运行正常,但太耗时和消耗资源。特别是,当我为完整数据集运行它时。我想知道是否有办法优化它并减少所需的处理资源和时间,以保持 overlapwindow_size 值相同。

library(foreach)
library(doParallel)

cores=parallel::detectCores()
cl <- makeCluster(cores-1) 
registerDoParallel(cl)

overlap <- 32
window_size <- 512

start_pos <- seq(1,20480,by = overlap)

lst_B2_512_32 <- list()

##Edit: changed the fixed 2156 length of the loop to length(unique(test_1st_binded_B2$ID)
lst_B2_512_32 <- foreach(i=1:length(unique(test_1st_binded_B2$ID)),.verbose = T) %dopar% {
  lst_B2_512_32[[i]] <- lapply(start_pos,function(x) test_1st_binded_B2[test_1st_binded_B2$ID==i,][(c(x:(x + window_size-1))),])
}

这是'dput(head(test_1st_binded_B2))'的结果

structure(list(B2_X = c(-0.183,-0.164,-0.195,-0.159,-0.261,-0.281),B2_Y = c(-0.054,-0.183,-0.125,-0.178,-0.098,-0.125
),ID = c(1L,1L,1L)),row.names = c(NA,6L),class = "data.frame")

*Edit - 这段代码不是使用 dput 结果,而是帮助重现“test_1st_binded_B2”数据框架,并通过更改 n 的值轻松缩放它。

n <- 2
B2x <- rnorm(20480*n,mean = 0,sd = 1)
B2y <- rnorm(20480*n,sd = 1)
id <- 1:n

test_1st_binded_B2 <- data.frame(B2_X = B2x,B2_Y = B2y,ID = id)

原始 test_1st_binded_B2 共有 44154880 个观察值,其中包含 2156 个 ID 中每个 ID 的 20480 个观察值。它是轴承运行失效模拟数据的一部分。

解决方法

有几种方法可能会有所帮助。除非有更具体的用例,否则我建议暂时远离 foreach

library (data.table)
dt = as.data.table(test_1st_binded_B2)
dt[,.(lapply(start_pos,function(i) .SD[i:(i + window_size - 1L)])),by = ID]

使用 包,我们可以利用高性能分组。在原始示例中,每个分组都是子集。也就是说,任何时候我们遇到分组问题 DF[ grp == this_grp,] 都意味着我们必须不断比较分组列。相反,分组使我们能够更有效地拆分和应用我们的功能。

更进一步,lapply(starts,function(i) DF[i:(i + window_size - 1),] 可能有点低效,因为我们构建了一个更大的数据框或列表。我们可以改为直接对分组数据进行子集化。

dt[,.SD[sequence(rep.int(window_size,length(start_pos)),start_pos)
         ][,list(list(.SD)),by = gl(length(start_pos),window_size)],by = ID]

系统时间为:

OP - 1.59 秒

第一个选项 - 0.32 秒

第二个选项 - 0.08 秒