对此的简单答案是“购买更多 RAM”,但我希望得到更有建设性的答案并在此过程中学到一些东西。
我正在运行 Windows 7 64 位和 8GB RAM。
我有几个非常大的 .csv.gz 文件(约 450MB 未压缩),它们的标题信息与我读入 R 并执行一些处理的完全相同。然后,我需要将处理后的 R 对象组合成一个主对象并写回磁盘上的 .csv。
我对多组文件执行相同的操作。例如,我有 5 个文件夹,每个文件夹中有 6 个 csv.gz 文件。我最终需要 5 个主文件,每个文件夹一个。
我的代码如下所示:
for( loop through folders ){
master.file = data.table()
for ( loop through files ) {
filename = list.files( ... )
file = as.data.table ( read.csv( gzfile( filename ), stringsAsFactors = F ))
gc()
...do some processing to file...
# append file to the running master.file
if ( nrow(master.file) == 0 ) {
master.file = file
} else {
master.file = rbindlist( list( master.file, file) )
}
rm( file, filename )
gc()
}
write.csv( master.file, unique master filename, row.names = FALSE )
rm( master.file )
gc()
}
此代码不起作用。在写出最终的 csv 之前,我得到 cannot allocate memory
错误。我在运行此代码时正在观看资源监视器,但不明白为什么它会使用 8GB 的 RAM 来执行此处理。所有文件大小的总和大约为 2.7GB,所以我预计 R 将使用的最大内存为 2.7GB。但是 write.csv 操作似乎使用与您正在写入的数据对象相同的内存量,因此如果您在内存中有一个 2.7GB 的对象并尝试将其写出,您将使用 5.6GB 的内存。
这个明显的现实,加上使用 for
循环,其中内存似乎没有得到充分释放,似乎是问题所在。
我怀疑我可以使用提到的 sqldf
包 here和 here但是当我将 sqldf
语句设置为等于 R 变量时,我最终遇到了相同的内存不足错误。
最佳答案
2013 年 12 月 23 日更新 - 以下解决方案可在 R 中全部运行而不会耗尽内存
(感谢@AnandaMahto)。
这种方法的主要警告是,您必须绝对确保每次读入和写出的文件具有完全相同的标题列,顺序完全相同,或者您的 R 处理代码必须确保这一点,因为 write.table 确实不要为你检查这个。
for( loop through folders ){
for ( loop through files ) {
filename = list.files( ... )
file = as.data.table ( read.csv( gzfile( filename ), stringsAsFactors = F ))
gc()
...do some processing to file...
# append file to the running master.file
if ( first time through inner loop) {
write.table(file,
"masterfile.csv",
sep = ",",
dec = ".",
qmethod = "double",
row.names = "FALSE")
} else {
write.table(file,
"masterfile.csv",
sep = ",",
dec = ".",
qmethod = "double",
row.names = "FALSE",
append = "TRUE",
col.names = "FALSE")
}
rm( file, filename )
gc()
}
gc()
}
我的初步解决方案:
for( loop through folders ){
for ( loop through files ) {
filename = list.files( ... )
file = as.data.table ( read.csv( gzfile( filename ), stringsAsFactors = F ))
gc()
...do some processing to file...
#write out the file
write.csv( file, ... )
rm( file, filename )
gc()
}
gc()
}
然后我下载并安装了GnuWin32's sed package并使用 Windows 命令行工具将文件追加如下:
copy /b *common_pattern*.csv master_file.csv
这会将名称中包含文本模式“common_pattern”的所有单个 .csv 文件、标题和所有文件附加在一起。
然后我使用 sed.exe 删除除第一个标题行之外的所有内容,如下所示:
"c:\Program Files (x86)\GnuWin32\bin\sed.exe" -i 2,${/header_pattern/d;} master_file.csv
-i
告诉 sed 只覆盖指定的文件(就地)。
2,$
告诉 sed 查看从第 2 行到最后一行 ($) 的范围
{/header_pattern/d;}
告诉 sed 查找范围内所有包含文本“header_pattern”的行,然后 d
删除这些行
为了确保这是我想要的,我首先打印了我打算删除的行。
"c:\Program Files (x86)\GnuWin32\bin\sed.exe" -n 2,${/header_pattern/p;} master_file.csv
工作就像一个魅力,我只希望我能在 R 中完成这一切。
关于r - 如何将多个大型 data.table 对象附加到单个 data.table 并快速导出到 csv 而不会耗尽内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20712996/