阅读许多相关文件

假设我们想要读取和堆叠一堆类似格式的文件。快速解决方案是:

rbindlist(lapply(list.files(patt="csv$"), fread), id=TRUE)

我们可能不满意这有几个原因:

  • 使用 fread 读取时或者由于数据格式不一致或错误而与 rbindlist 堆叠时,可能会出错。
  • 我们可能希望跟踪每个文件的元数据,从文件名中抓取,或者可能从(非常表格)文件中的某些标题行中获取。

处理此问题的一种方法是创建文件表并将每个文件的内容存储为与其关联的行上的列表列条目。

示例数据

在制作下面的示例数据之前,请确保你处于可以写入的空文件夹中。如果你需要更改文件夹,请运行 getwd() 并阅读 ?setwd

# example data
set.seed(1)
for (i in 1:3) 
  fwrite(data.table(id = 1:2, v = sample(letters, 2)), file = sprintf("file201%s.csv", i))

识别文件和文件元数据

这部分相当简单:

# First, identify the files you want:
fileDT = data.table(fn = list.files(pattern="csv$"))

# Next, optionally parse the names for metadata using regex:
fileDT[, year := type.convert(sub(".*([0-9]{4}).*", "\\1", fn))]

# Finally construct a string file-ID column:
fileDT[, id := as.character(.I)]

#              fn year id
# 1: file2011.csv 2011  1
# 2: file2012.csv 2012  2
# 3: file2013.csv 2013  3

读入文件

以列表列的形式读入文件:

fileDT[, contents := .(lapply(fn, fread))]

#              fn year id     contents
# 1: file2011.csv 2011  1 <data.table>
# 2: file2012.csv 2012  2 <data.table>
# 3: file2013.csv 2013  3 <data.table>

如果在阅读其中一个文件时遇到障碍,或者你需要根据文件的属性将参数更改为 fread,则可以轻松扩展此步骤,如下所示:

fileDT[, contents := {
  cat(fn, "\n")

  dat = if (year %in% 2011:2012){
    fread(fn, some_args)
  } else {
    fread(fn)
  }

  .(.(dat))
}, by=fn]

有关读取 CSV 和类似文件的选项的详细信息,请参阅 ?fread

堆栈数据

从这里,我们想要堆叠数据:

fileDT[, rbindlist(setNames(contents, id), idcol="file_id")]

#    file_id id v
# 1:       1  1 g
# 2:       1  2 j
# 3:       2  1 o
# 4:       2  2 w
# 5:       3  1 f
# 6:       3  2 w

如果堆叠中出现问题(如列名或类不匹配),我们可以返回到 fileDT 中的各个表来检查问题的来源。例如,

fileDT[id == "2", contents[[1]]]
#    id v
# 1:  1 o
# 2:  2 w

扩展

如果文件不在你当前工作的目录中,请使用

my_dir = "whatever"
fileDT = data.table(fn = list.files(my_dir, pattern="*.csv"))

# and when reading
fileDT[, contents := .(lapply(fn, function(n) fread(file.path(my_dir, n))))]