r - 如何将多个大型 data.table 对象附加到单个 data.table 并快速导出到 csv 而不会耗尽内存?

标签 r memory csv data.table sqldf

对此的简单答案是“购买更多 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 循环,其中内存似乎没有得到充分释放,似乎是问题所在。

我怀疑我可以使用提到的 sqldfherehere但是当我将 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/

相关文章:

r - src_postgres 和 dbConnect 函数将 R 与 postgres 连接的区别

r - 在代理后面密谋访问

r - 如何在 Azure 上交互式运行 Docker 容器

java - JBOSS占用CPU超过100%

java - 使用 SuperCSV 跳过 CSV 文件中的可选 header

r - mgcv中的循环自适应样条

C - 数组代码中奇怪的 Valgrind 投诉

Delphi 的 Sharemem - 不需要时

Python:根据字符数拆分 CSV

php - 根据列值合并/粘贴 csv 文件