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

 -DJIAJIAN- 发布于 2023-02-08 19:15

对此的简单回答是"购买更多内存",但我希望得到更具建设性的答案,并在此过程中学到一些东西.

我运行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

1 个回答
  • 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中做到这一切.

    2023-02-08 19:17 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有