将许多.csv文件导入R的最快方法是什么?



假设我们有一个包含许多.csv文件的文件夹,每个文件包含相同的列,每个列具有不同的数据。什么是最快的方法来读取它们到一个R data.frame/data.table?

一个类似的问题在2012年被问到。如果有人在使用之前数据的R版本。表发布(2008年8月),请访问该问题。

是时候将121401个csv读取到单个data.table中了。每次是三次运行的平均值,然后四舍五入。每个csv有3列,一个标题行,平均有4.510行。Machine为96核GCP VM

rbindlist lapply read.delim  500s
rbindlist lapply fread       250s    (example at end)
rbindlist mclapply fread      10s    (example at end)
fread cat                      5s <- fastest; main topic of this answer

readcat解决方案使用catshell命令将所有文件连接在一起,然后使用数据。表的fread阅读结果:

x = fread(cmd='cat *.csv', header=F)

但是,如果每个csv都有一个头呢?将它们全部连接起来会在许多标题中混合数据行。

x = fread(cmd="awk 'NR==1||FNR!=1' *.csv", header=T)

如果你有太多的文件,*.csvshell glob失败了怎么办?

x = fread(cmd='find . -name "*.csv" | xargs cat', header=F)

如果所有的文件都有一个头并且有太多的文件怎么办?

header = fread(cmd='find . -name "*.csv" | head -n1 | xargs head -n1', header=T)
x = fread(cmd='find . -name "*.csv" | xargs tail -q -n+2', header=F)
setnames(x,header)

如果结果连接的csv对于系统内存来说太大怎么办?(例如,/dev/shm out of space错误)

system('find . -name "*.csv" | xargs cat > combined.csv')
x = fread('combined.csv', header=F)

头吗?

system('find . -name "*.csv" | head -n1 | xargs head -n1 > combined.csv')
system('find . -name "*.csv" | xargs tail -q -n+2 >> combined.csv')
x = fread('combined.csv', header=T)

如果您不想要目录中所有的.csv文件,而是要特定的一组文件,该怎么办?而且,它们都有标题。

fread(text=paste0(system("xargs cat|awk 'NR==1||$1!="<column one name>"'",input=paths,intern=T),collapse="n"),header=T,sep="t")
下面是我在生产环境中使用的一个函数来处理这些情况,但是在信任它之前,您应该用自己的数据对它进行彻底的测试。若要为每个csv的inpath包含一列,请使用keep_inpath=T并使用sep参数显式指定csv分隔符。
fread_many = function(files,header=T,keep_inpath=F,sep="auto",...){
if(length(files)==0) return()
if(typeof(files)!='character') return()
files = files[file.exists(files)]
if(length(files)==0) return()
# note 1: requires awk, not cat or tail because some files have no final newline
# note 2: parallel --xargs is 40% slower
# note 3: reading to var is 15% slower and crashes R if the string is too long
# note 4: shorter paths -> more paths per awk -> fewer awks -> measurably faster
#         so best cd to the csv dir and use relative paths
tmp = tempfile(fileext = ".csv")
if(keep_inpath==T){
stopifnot(sep!="auto")
if(header==T){
system(paste0('/usr/bin/echo -ne inpath"',sep,'" > ',tmp))
system(paste0('head -n1 ',files[1],' >> ',tmp))
system(paste0("xargs awk -vsep='",sep,"' 'BEGIN{OFS=sep}{if(FNR>1)print FILENAME,$0}' >> ",tmp),input=files)
} else {
system(paste0("xargs awk -vsep='",sep,"' 'BEGIN{OFS=sep}{print FILENAME,$0}' > ",tmp),input=files)
}
} else {
if(header==T){
system(paste0('head -n1 ',files[1],' > ',tmp))
system(paste0("xargs awk 'FNR>1' >> ",tmp),input=files)
} else {
system(paste0("xargs awk '1' > ",tmp),input=files)
}
}
DT = fread(file=tmp,header=header,sep=sep,...)
file.remove(tmp)
DT
}

警告:在读取csv之前连接它们的所有解决方案都假设它们具有相同的分隔符。如果不是所有csv都使用相同的分隔符,那么可以分批使用rbindlist lapply fread、rbindlist mclapply fread或fread xargs cat,其中批处理中的所有csv都使用相同的分隔符。例子:

# single core: rbindlist lapply fread
x = rbindlist(lapply(files,fread)),use.names=T,fill=T)
# multicore: rbindlist mclapply fread
x = rbindlist(mclapply(files,fread)),use.names=T,fill=T)
# fread cat in batches
x = fread(cmd='cat format1/*.csv')
y = fread(cmd='cat format2/*.csv')
z = rbind(x,y,use.names=T,fill=T)

这是我第一次听说read cat: https://stackoverflow.com/a/11433740/1563960

相关内容