如何将多个大型 sas 数据文件读入 R、筛选行并将子集数据集另存为 .rds
How to read multiple large sas data files into R, filter rows and save subset datasets as .rds
我在一个文件夹中有 30 个 sas 文件(dataset1.sas7bdat 到 dataset30.sas7bdat,每个文件大约 10 GB),需要分析这些数据文件中的一部分行(字符变量所在的所有行) A 以 10) 开头。
因此,我需要将每个 sas 文件读入 R,使用 grep 对变量 A 过滤一个子集,然后将每个过滤后的数据集保存为 .rds 文件。
我正在尝试使用 list.files() 的 for 循环和 Haven 包来读取 sas 文件来实现此目的。为了避免内存不足,我需要在子集被过滤并保存为 .rds 后,在每次迭代中删除导入的数据集。
虽然不优雅也不令人满意,但我可以像这样手动硬编码 30 次,copy/pasting 每次后缀递增 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() 函数的方法中。
有没有更好的方法来解决这个问题?
您可以通过
在每次加载和过滤后清除内存来考虑释放内存
rm(list=ls())
我睡了一觉,醒来时发现了一个可行的解决方案,它使用一个函数来完成工作,并使用一个循环来循环文件名。这也使我能够将输出保存在不同的文件夹中(我的原始数据文件夹是只读的):
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 个文件对此进行测试。今晚我会这样做。
如果我遇到问题,我会在明天 post 更新。否则,这个问题可以在 48 小时内关闭。
更新:它工作顺利,在大约 13 小时内完成了 297GB 的转换。我不认为可以对其进行优化以更快地完成任务;绝大多数计算时间都花在了打开 sas 文件上,我认为除了避风港以外,没有其他方法可以更快地打开它。除非有人有优化流程的想法,否则这个问题可以关闭。
我在一个文件夹中有 30 个 sas 文件(dataset1.sas7bdat 到 dataset30.sas7bdat,每个文件大约 10 GB),需要分析这些数据文件中的一部分行(字符变量所在的所有行) A 以 10) 开头。 因此,我需要将每个 sas 文件读入 R,使用 grep 对变量 A 过滤一个子集,然后将每个过滤后的数据集保存为 .rds 文件。 我正在尝试使用 list.files() 的 for 循环和 Haven 包来读取 sas 文件来实现此目的。为了避免内存不足,我需要在子集被过滤并保存为 .rds 后,在每次迭代中删除导入的数据集。
虽然不优雅也不令人满意,但我可以像这样手动硬编码 30 次,copy/pasting 每次后缀递增 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() 函数的方法中。 有没有更好的方法来解决这个问题?
您可以通过
在每次加载和过滤后清除内存来考虑释放内存rm(list=ls())
我睡了一觉,醒来时发现了一个可行的解决方案,它使用一个函数来完成工作,并使用一个循环来循环文件名。这也使我能够将输出保存在不同的文件夹中(我的原始数据文件夹是只读的):
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 个文件对此进行测试。今晚我会这样做。 如果我遇到问题,我会在明天 post 更新。否则,这个问题可以在 48 小时内关闭。
更新:它工作顺利,在大约 13 小时内完成了 297GB 的转换。我不认为可以对其进行优化以更快地完成任务;绝大多数计算时间都花在了打开 sas 文件上,我认为除了避风港以外,没有其他方法可以更快地打开它。除非有人有优化流程的想法,否则这个问题可以关闭。