使用嵌入式 lapply 循环优化 foreach - 是否可以优化代码?
Optimizing a foreach with an embeded lapply loop - Is it possible to optimize code?
我有下面的代码块 运行ning 正确但太耗时和资源。特别是,当我 运行 它用于完整数据集时。我想知道是否有优化它并减少所需的处理资源和时间保持 overlap 和 window_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, 1L, 1L, 1L)), row.names = c(NA, 6L), class = "data.frame")
*编辑 - 此代码片段不使用 dput 结果,而是帮助重现“test_1st_binded_B2”data.frame 并通过更改 n.
的值轻松缩放它
n <- 2
B2x <- rnorm(20480*n, mean = 0, sd = 1)
B2y <- rnorm(20480*n, mean = 0, 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中的每一个的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]
使用data.table包,我们可以利用高性能分组。在原始示例中,每个分组都被子集化。也就是说,任何时候我们遇到分组问题 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 秒
我有下面的代码块 运行ning 正确但太耗时和资源。特别是,当我 运行 它用于完整数据集时。我想知道是否有优化它并减少所需的处理资源和时间保持 overlap 和 window_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, 1L, 1L, 1L)), row.names = c(NA, 6L), class = "data.frame")
*编辑 - 此代码片段不使用 dput 结果,而是帮助重现“test_1st_binded_B2”data.frame 并通过更改 n.
的值轻松缩放它n <- 2
B2x <- rnorm(20480*n, mean = 0, sd = 1)
B2y <- rnorm(20480*n, mean = 0, 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中的每一个的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]
使用data.table包,我们可以利用高性能分组。在原始示例中,每个分组都被子集化。也就是说,任何时候我们遇到分组问题 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 秒