使用R跨子目录合并许多大型CSV文件

时间:2019-05-07 10:09:09

标签: r csv

我有300多个具有相同文件名的大型CSV文件,每个文件都位于单独的子目录中,我想使用R合并到单个数据集中。我正在寻求有关如何删除我不希望的列的帮助不需要在每个CSV文件中进行合并,而合并的方式则可以将进程分解为较小的块,以便我的内存可以更轻松地处理。

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

我的每个CSV本身都非常大(大约80列,其中许多是不必要的,并且每个文件都有成千上万的行),并且总共有近1600万个观测值,或大约12GB。 / p>

我已经编写了一些代码,可以成功地针对两个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文件合并为几个RDS文件,以供以后合并,或者通过循环累积到单个RDS文件中。

但是,我不知道如何进行这些操作-我对R还是很陌生,对于在进行1)和2)方面的处理方面的任何帮助,将不胜感激。

谢谢

1 个答案:

答案 0 :(得分:0)

对于一个对象,十二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无法进行分块和磁盘上的交互,因此您只能使用平面文件(或者使用上面提到的其他选项之一)。