我有一个大型数据框,54k 行,38k 列。我的目标是在此数据帧上运行一个简单的函数 test_func。
test_func
需要使用 8 个包含通用信息的索引列,例如日期和时间以及数值。然后,我有 38k 不同的整数数据列 (0,1),我想逐一运行 test_func() 并存储结果。
我最初假设执行此操作的最佳方法是获取大型数据帧并将其拆分为数据帧列表,其中列表的每个元素都有一个数据帧,其中包含索引列以及要测试的变量列之一当前迭代。我认为这是最好的方法,这样就不必在每次循环迭代时操作大数据帧。
大型数据帧的拆分是通过
lapply
使用以下代码实现的,这些代码来自本文中收到的帮助(将数据帧按列拆分为数据帧列表,同时保留索引列和单个变量列)。
set.seed(123)
df <- data.frame(a = rnorm(10, 5, 1), b = rnorm(10, 5, 1), c = rnorm(10, 5, 1), z = rnorm(10, 5, 1), y = rnorm(10, 5, 1), x = rnorm(10, 5, 1))
split_df_by_col <- function(df, index_cols) {
cols_to_split <- setdiff(names(df), index_cols)
lapply(cols_to_split, \(col) cbind(df[, c(index_cols, col)], type = col))
}
df_lst <- split_df_by_col(df, index_cols = c("a", "b", "c"))
但是,当我将其应用于占用 9.303434 GB 内存的数据帧时,我的数据帧列表 df_lst 现在占用 223.198 GB。然后,我将 df_lst 传递给
foreach()
函数,该函数使用并行处理迭代列表中的每个数据帧,如下所示
# set up cluster
ncores <- detectCores(logical = FALSE) - 1
myCluster <- makeCluster(ncores, type = "FORK", outfile="")
registerDoParallel(myCluster)
run <- foreach(i = seq_along(df_lst), .errorhandling='pass', %dopar% {
flt_dat <- df_lst[[i]]
res <- test_function()
return(res)
}
# shut down cluster
stopCluster(myCluster)
不幸的是,这会导致 R 崩溃并且运行失败。我知道该运行在较小的数据集上运行完美,因为我已经在具有 5k cols 的数据帧上测试了它,并且运行良好。
解决这个问题的最佳方法是什么?
避免不必要的数据副本。
这应该说明如何解决这个问题:
library(foreach)
ix <- df[, index_cols]
dat <- df[, !colnames(df) %in% index_cols]
foreach(x = dat, n = names(dat)) %do% {
cbind(ix, setNames(list(x), n))
}
您不共享该函数,但最好专注于优化该函数的性能并重新设计整个方法并消除对
foreach
循环的需要。