使用方便 I/O 将大列表分成块
Partition a large list into chunks with convenient I/O
我有一个很大的列表,大小约为。 1.3GB。我正在寻找 R 中生成块并以任何方便的格式保存它们的最快解决方案,以便:
a) chunk的每个保存文件小于100MB large
b) 可以方便快捷地将原始列表加载到新的 R 工作区
EDIT II:这样做的原因是 R 解决方案绕过 GitHub 每个文件 100MB 的文件大小限制。对 R 的限制是由于一些我无法评论的外部非技术限制。
这个问题的最佳解决方案是什么?
编辑 I:由于评论中提到该问题的一些代码有助于创建更好的问题:
大小为 1.3 GB 的列表的 R 示例:
li <- list(a = rnorm(10^8),
b = rnorm(10^7.8))
所以,您想拆分一个文件并在单个数据帧中重新加载它。
有一个转折点:要减小文件大小,压缩是明智的,但文件大小并不完全确定。您可能需要调整一个参数。
以下是我用于类似任务的一段代码(尽管与 GitHub 无关)。
split.file
函数有 3 个参数:数据帧、每个文件中要写入的行数以及基本文件名。例如,如果 basename 是“myfile”,则文件将是“myfile00001.rds”、“myfile00002.rds”等。
函数returns写入的文件数
join.files
函数采用基本名称。
注:
- 使用
rows
参数找出适合 100 MB 的正确大小。这取决于您的数据,但对于类似的数据集,固定大小应该可以。但是,如果您处理的是非常不同的数据集,这种方法可能会失败。
- 读取时,你需要有两倍于你的dataframe占用的内存(因为先读取较小的dataframes列表,然后再绑定。
- 该号码写为 5 位数字,但您可以更改它。目标是按字典顺序排列名称,以便在连接文件时,行的顺序与原始文件的顺序相同。
函数如下:
split.file <- function(db, rows, basename) {
n = nrow(db)
m = n %/% rows
for (k in seq_len(m)) {
db.sub <- db[seq(1 + (k-1)*rows, k*rows), , drop = F]
saveRDS(db.sub, file = sprintf("%s%.5d.rds", basename, k),
compress = "xz", ascii = F)
}
if (m * rows < n) {
db.sub <- db[seq(1 + m*rows, n), , drop = F]
saveRDS(db.sub, file = sprintf("%s%.5d.rds", basename, m+1),
compress = "xz", ascii = F)
m <- m + 1
}
m
}
join.files <- function(basename) {
files <- sort(list.files(pattern = sprintf("%s[0-9]{5}\.rds", basename)))
do.call("rbind", lapply(files, readRDS))
}
示例:
n <- 1500100
db <- data.frame(x = rnorm(n))
split.file(db, 100000, "myfile")
dbx <- join.files("myfile")
all(dbx$x == db$x)
我有一个很大的列表,大小约为。 1.3GB。我正在寻找 R 中生成块并以任何方便的格式保存它们的最快解决方案,以便:
a) chunk的每个保存文件小于100MB large
b) 可以方便快捷地将原始列表加载到新的 R 工作区
EDIT II:这样做的原因是 R 解决方案绕过 GitHub 每个文件 100MB 的文件大小限制。对 R 的限制是由于一些我无法评论的外部非技术限制。
这个问题的最佳解决方案是什么?
编辑 I:由于评论中提到该问题的一些代码有助于创建更好的问题:
大小为 1.3 GB 的列表的 R 示例:
li <- list(a = rnorm(10^8),
b = rnorm(10^7.8))
所以,您想拆分一个文件并在单个数据帧中重新加载它。
有一个转折点:要减小文件大小,压缩是明智的,但文件大小并不完全确定。您可能需要调整一个参数。
以下是我用于类似任务的一段代码(尽管与 GitHub 无关)。
split.file
函数有 3 个参数:数据帧、每个文件中要写入的行数以及基本文件名。例如,如果 basename 是“myfile”,则文件将是“myfile00001.rds”、“myfile00002.rds”等。
函数returns写入的文件数
join.files
函数采用基本名称。
注:
- 使用
rows
参数找出适合 100 MB 的正确大小。这取决于您的数据,但对于类似的数据集,固定大小应该可以。但是,如果您处理的是非常不同的数据集,这种方法可能会失败。 - 读取时,你需要有两倍于你的dataframe占用的内存(因为先读取较小的dataframes列表,然后再绑定。
- 该号码写为 5 位数字,但您可以更改它。目标是按字典顺序排列名称,以便在连接文件时,行的顺序与原始文件的顺序相同。
函数如下:
split.file <- function(db, rows, basename) {
n = nrow(db)
m = n %/% rows
for (k in seq_len(m)) {
db.sub <- db[seq(1 + (k-1)*rows, k*rows), , drop = F]
saveRDS(db.sub, file = sprintf("%s%.5d.rds", basename, k),
compress = "xz", ascii = F)
}
if (m * rows < n) {
db.sub <- db[seq(1 + m*rows, n), , drop = F]
saveRDS(db.sub, file = sprintf("%s%.5d.rds", basename, m+1),
compress = "xz", ascii = F)
m <- m + 1
}
m
}
join.files <- function(basename) {
files <- sort(list.files(pattern = sprintf("%s[0-9]{5}\.rds", basename)))
do.call("rbind", lapply(files, readRDS))
}
示例:
n <- 1500100
db <- data.frame(x = rnorm(n))
split.file(db, 100000, "myfile")
dbx <- join.files("myfile")
all(dbx$x == db$x)