对此的简单回答是"购买更多内存",但我希望得到更具建设性的答案,并在此过程中学到一些东西.
我运行Windows 7 64位,内存为8GB.
我有几个非常大的.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() }
此代码不起作用.我cannot allocate memory
在写出最终的csv之前得到了错误.我在运行此代码时正在观察资源监视器,并且不明白为什么要使用8GB的RAM来执行此处理.所有文件大小的总和大约是2.7GB,所以我期望R将使用的最大内存为2.7GB.但write.csv操作似乎使用与您正在编写的数据对象相同的内存量,因此如果您在内存中有一个2.7GB的对象并尝试将其写出来,那么您将使用5.6 GB的内存.
这个明显的现实,加上使用一个for
循环,其中内存似乎没有得到充分释放似乎是问题.
我怀疑我可以使用这里和这里sqldf
提到的包但是当我将语句设置为等于R变量时,我最终得到了相同的内存不足错误.sqldf
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的sed软件包,并使用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中做到这一切.