读取 100,000 个 .dat.gz 文件的最快方法

Fastest way to read in 100,000 .dat.gz files

我有几十万个非常小的 .dat.gz 文件,我想以最有效的方式读入 R。我读入文件,然后立即聚合并丢弃数据,因此我不用担心在进程接近尾声时管理内存。我只是想加速瓶颈,恰好是解压和读入数据。

每个数据集由 366 行和 17 列组成。这是我目前正在做的一个可重现的例子:

构建可重现的数据:

require(data.table)

# Make dir
system("mkdir practice")

# Function to create data
create_write_data <- function(file.nm) {
  dt <- data.table(Day=0:365)
  dt[, (paste0("V", 1:17)) := lapply(1:17, function(x) rnorm(n=366))]
  write.table(dt, paste0("./practice/",file.nm), row.names=FALSE, sep="\t", quote=FALSE)
  system(paste0("gzip ./practice/", file.nm))    
}

这里是应用代码:

# Apply function to create 10 fake zipped data.frames (550 kb on disk)
tmp <- lapply(paste0("dt", 1:10,".dat"), function(x) create_write_data(x))

这是我迄今为止读取数据最有效的代码:

# Function to read in files as fast as possible
read_Fast <- function(path.gz) {
  system(paste0("gzip -d ", path.gz)) # Unzip file
  path.dat <- gsub(".gz", "", path.gz)
  dat_run <- fread(path.dat)
}

# Apply above function
dat.files <- list.files(path="./practice", full.names = TRUE)
system.time(dat.list <- rbindlist(lapply(dat.files, read_Fast), fill=TRUE))
dat.list

我已经将它封装在一个函数中并并行应用它,但对于我需要它的用途来说它仍然太慢了。

我已经尝试了很棒的 h2o 包中的 h2o.importFolder,但与使用 Rdata.table 相比,它实际上要慢得多。也许有一种方法可以加快文件的解压缩速度,但我不确定。从我有几次 运行 开始,我注意到文件的解压缩通常需要大约 2/3 的功能时间。

瓶颈可能是由使用 system() 调用外部应用程序引起的。

您应该尝试使用构建函数来提取存档。 这个答案解释了如何:Decompress gz file using R

R 可以使用 gzfile 函数本地读取 gzip 文件。看看这是否有效。

rbindlist(lapply(dat.files, function(f) {
    read.delim(gzfile(f))
}))

我有点惊讶这居然奏效了。希望它适用于您的情况。我很想知道速度与直接从 R 中从磁盘读取压缩数据相比速度如何(尽管有非矢量化的惩罚)。

tblNames = fread('cat *dat.gz | gunzip | head -n 1')[, colnames(.SD)]
tbl = fread('cat *dat.gz | gunzip | grep -v "^Day"')
setnames(tbl, tblNames)
tbl