【问题标题】:Using R to merge many large CSV files across sub-directories使用 R 跨子目录合并许多大型 CSV 文件
【发布时间】:2019-05-07 10:09:08
【问题描述】:

我有超过 300 个具有相同文件名的大型 CSV 文件,每个文件位于一个单独的子目录中,我想使用 R 将它们合并到一个数据集中。我正在寻求有关如何删除我没有的列的帮助不需要在每个 CSV 文件中,同时以一种将过程分解成更小的块的方式进行合并,以便我的内存更容易处理。

我的目标是创建一个 CSV 文件,然后我可以将其导入 STATA 以使用我已经编写并在其中一个文件上测试过的代码进行进一步分析。

我的每个 CSV 本身都相当大(大约 80 列,其中许多是不必要的,每个文件有数万到数十万行),总共有近 1600 万个观察值,或大约 12GB。

我已经编写了一些代码,可以成功地为两个 CSV 的测试用例做到这一点。挑战在于我的工作和个人计算机都没有足够的内存来为所有 300 多个文件执行此操作。

我试过的代码在这里:

library(here) ##installs package to find files

( allfiles = list.files(path = here("data"), ##creates a list of the files, read as [1], [2], ... [n]
                        pattern = "candidates.csv", ##[identifies the relevant files]
                        full.names = TRUE, ##identifies the full file name
                        recursive = TRUE) ) ##searches in sub-directories

read_fun = function(path) {
  test = read.csv(path,
                  header = TRUE ) 
  test
} ###reads all the files

(test = read.csv(allfiles,
                 header = TRUE ) )###tests that file [1] has been read

library(purrr) ###installs package to unlock map_dfr

library(dplyr) ###installs packages to unlock map_dfr

( combined_dat = map_dfr(allfiles, read_fun) )

我希望结果是单个 RDS 文件,这适用于测试用例。不幸的是,当查看我所有文件的 15.5m 观察值时,此过程所需的内存量导​​致 RStudio 崩溃,并且没有生成 RDS 文件。

我正在寻求有关以下方面的帮助: 1) 通过删除我不需要的 CSV 文件中的一些变量(标题为 junk1junk2 等的列)来减少内存负载;和 2) 如何以更易于管理的方式合并我的 CSV 文件,将我的 CSV 文件按顺序合并到几个 RDS 文件中,然后再合并,或者通过循环累积到单个 RDS 文件中。

但是,我不知道如何继续这些 - 我对 R 还是新手,非常感谢任何关于如何继续 1) 和 2) 的帮助。

谢谢,

【问题讨论】:

    标签: r csv


    【解决方案1】:

    12 GB 对于一个对象来说是相当多的。除非您拥有超过 12GB 的 RAM,否则使用单个 RDS 或 CSV 可能不切实际。您可能想考虑使用database,这是一种专为此类事情设计的技术。我确信 Stata 也可以与数据库交互。您可能还想了解如何使用 various strategies and packages 与大型 CSV 进行交互。

    创建大型 CSV 一点也不难。请记住,您必须在未来某个时候使用上述巨型 CSV,这可能会很困难。要创建大型 CSV,只需单独处理每个组件 CSV,然后将它们附加到新 CSV。以下内容读取每个 CSV,删除不需要的列,然后将生成的数据框附加到平面文件:

    library(dplyr)
    library(readr)
    library(purrr)
    
    load_select_append <- function(path) {
        # Read in CSV. Let every column be of class character.
        df <- read_csv(path, col_types = paste(rep("c", 82), collapse = ""))
    
        # Remove variables beginning with "junk"
        df <- select(df, -starts_with("junk"))
    
        # If file exists, append to it without column names, otherwise create with
        # column names.
        if (file.exists("big_csv.csv")) {
            write_csv(df, "big_csv.csv", col_names = F, append = T)
        } else {
            write_csv(df, "big_csv.csv", col_names = T)
        }
    }
    
    
    # Get the paths to the CSVs.
    csv_paths <- list.files(path = "dir_of_csvs",
                            pattern = "\\.csv.*",
                            recursive = T, 
                            full.names = T
                            )
    
    # Apply function to each path.
    walk(csv_paths, load_select_append)
    

    当您准备好使用 CSV 时,您可能需要考虑使用类似 ff 的包,它可以与磁盘上的对象进行交互。您对 ffdf 对象的操作有些限制,因此最终您将不得不使用示例:

    library(ff)
    
    df_ff <- read.csv.ffdf(file = "big_csv.csv")
    df_samp <- df_ff[sample.int(nrow(df_ff), size = 100000),]
    df_samp <- mutate(df_samp, ID = factor(ID))
    
    summary(df_samp)
    
    #### OUTPUT ####
    
         values             ID       
     Min.   :-9.861   17267  :    6  
     1st Qu.: 6.643   19618  :    6  
     Median :10.032   40258  :    6  
     Mean   :10.031   46804  :    6  
     3rd Qu.:13.388   51269  :    6  
     Max.   :30.465   52089  :    6  
                      (Other):99964 
    

    据我所知,RDS 或 RDA 无法进行分块和磁盘交互,因此您只能使用平面文件(或者选择我上面提到的其他选项之一)。

    【讨论】:

      猜你喜欢
      • 2015-04-01
      • 2016-04-09
      • 1970-01-01
      • 1970-01-01
      • 2020-09-23
      • 2012-04-29
      • 1970-01-01
      • 2016-09-01
      • 1970-01-01
      相关资源
      最近更新 更多