使用方便 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)