0

我在一个文件夹中有 30 个 sas 文件(dataset1.sas7bdat 到 dataset30.sas7bdat,每个文件大约 10 GB),需要分析这些数据文件中的行子集(字符变量 A 以 10 开头的所有行) . 因此,我需要将每个 sas 文件读入 R,在变量 A 上使用 grep 过滤一个子集,然后将每个过滤后的数据集保存为 .rds 文件。我正在尝试使用 list.files() 的 for 循环和 Haven 包来读取 sas 文件来实现这一点。为了避免内存不足,在子集被过滤并保存为 .rds 之后,我需要在每次迭代中删除导入的数据集。

虽然不优雅也不令人满意,但我可以像这样手动硬编码 30 次,每次复制/粘贴并将后缀增加 1:

dt1 <- haven::read_sas("~/folder/dataset1.sas7bdat")
dt1 <- data.table::as.data.table(dt1)
dt1 <- dt1[grep("^10", A)]
saveRDS(dt1, "~/folder/subset1.rds")

dt2 <- haven::read_sas("~/folder/dataset2.sas7bdat")
dt2 <- data.table::as.data.table(dt2)
dt2 <- dt1[grep("^10", A)]
saveRDS(dt2, "~/folder/subset2.rds")
etc.

虽然以下 for 循环在技术上可以将文件读入内存,但由于大量内存不足,它永远不会完成,因此它不允许我过滤数据:

folder <- "~/folder/"
file_list <- list.files(path = folder, pattern = "^dataset")
for (i in 1:length(file_list)) {
 assign(file_list[i], Haven::read_sas(paste(folder, file_list[i], sep='')))
}

有没有办法 - 在循环中的每次迭代中 - 过滤数据集,删除未过滤的数据集并将子集保存在 .rds 文件中?我似乎无法想出一种方法将其合并到我使用 assign() 函数的方法中。有没有更好的方法来解决这个问题?

4

2 回答 2

0

您可以通过在每次加载和过滤后清除内存来释放内存

rm(list=ls())
于 2019-10-15T22:26:28.853 回答
0

我睡在上面,醒来后发现了一个工作解决方案,它使用一个函数来完成工作,并使用一个循环来循环文件名。这也使我能够将输出保存在不同的文件夹中(我的原始数据文件夹是只读的):

library(haven)
library(data.table)
fromFolder <- "~/folder_with_input_data/"
toFolder <- "~/folder_with_output_data/"
import_sas <- function(filename) {
dt <- read_sas(paste(fromFolder, filename, sep=''), NULL)
dt <- as.data.table(dt)
dt <- dt[grep("^10", A)]
saveRDS(dt, paste(toFolder,filename,'.rds.', sep =''), compress = FALSE)
remove(dt)
}

file_list <- list.files(path = fromFolder, pattern="^dataset")
for (filename in file_list) {
import_sas(filename)
}

我还没有用完整的 30 个文件对此进行测试。我今晚会这样做。如果我遇到问题,我会在明天发布更新。否则,这个问题可以在 48 小时内关闭。

更新:它运行顺利,在大约 13 小时内完成了 297GB 的转换。我不认为可以对其进行优化以更快地完成任务;绝大多数计算时间都花在了打开 sas 文件上,我认为除了 Haven 之外,其他方式都无法做到这一点。除非有人有优化流程的想法,否则这个问题可以关闭。

于 2019-10-16T06:46:40.910 回答