8

对此的简单答案是“购买更多 RAM”,但我希望得到更有建设性的答案并在此过程中学到一些东西。

我正在运行具有 8GB RAM 的 Windows 7 64 位。

我有几个非常大的 .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.6GB 的内存。

这个明显的现实,再加上使用一个for内存似乎没有得到充分释放的循环似乎是问题所在。

我怀疑我可以使用此处此处sqldf提到的包,但是当我将语句设置为等于 R 变量时,我最终遇到了相同的内存不足错误。sqldf

4

1 回答 1

5

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 中完成这一切。

于 2013-12-20T22:34:16.547 回答