【问题标题】:How to loop through a folder of CSV files in R如何遍历R中的CSV文件文件夹
【发布时间】:2017-02-25 02:04:54
【问题描述】:

我有一个文件夹,其中包含一堆标题为“yob1980”、“yob1981”、“yob1982”等的 CSV 文件。

我必须使用 for 循环遍历每个文件并将其内容放入数据框中 - 数据框中的列应为“1980”、“1981”、“1982”等

这是我所拥有的:

file_list <- list.files()

temp = list.files(pattern="*.txt")
babynames <- do.call(rbind,lapply(temp,read.csv, FALSE))

names(babynames) <- c("Name", "Gender", "Count")

我觉得我需要一个 for 循环,但我不确定如何循环文件。有人指出我正确的方向吗?

【问题讨论】:

  • CSV 文件是没有标题的一列文件吗?它们是否对应相同的记录 ID?
  • 您已经对所有文件执行了循环(lapply 对所有文件执行了隐式for 循环)。而且您已经在生成单个数据框 (do.call(rbind, ....))。问题是什么?
  • @Parfait CSV 文件没有标题,其中包含三列,其中包含名称、性别和该名称的计数
  • @MichaelGriffiths 我正在尝试向数据框中添加一列,其中包含名称对应的年份。
  • file_list 是干什么用的?

标签: r file loops csv


【解决方案1】:

使用咕噜声

library(tidyverse)

files <- list.files(path = "./data/", pattern = "*.csv")

df <- files %>% 
    map(function(x) {
        read.csv(paste0("./data/", x))
    }) %>%
    reduce(rbind)

【讨论】:

    【解决方案2】:

    我最喜欢的方法是使用plyr 包中的ldply。它具有返回数据帧的优点,因此您无需在之后执行 rbind 步骤:

    library( plyr )
    babynames <- ldply( .data = list.files(pattern="*.txt"),
                        .fun = read.csv,
                        header = FALSE,
                        col.names=c("Name", "Gender", "Count") )
    

    另外一个好处是,您可以非常轻松地进行多线程导入,从而大大加快导入大型多文件数据集的速度:

    library( plyr )
    library( doMC )
    registerDoMC( cores = 4 )
    babynames <- ldply( .data = list.files(pattern="*.txt"),
                        .fun = read.csv,
                        header = FALSE,
                        col.names=c("Name", "Gender", "Count"),
                        .parallel = TRUE )
    

    稍微更改上述内容以在结果数据框中包含Year 列,您可以先创建一个函数,然后在ldply 中执行该函数,就像执行read.csv 一样

    readFun <- function( filename ) {
    
        # read in the data
        data <- read.csv( filename, 
                          header = FALSE, 
                          col.names = c( "Name", "Gender", "Count" ) )
    
        # add a "Year" column by removing both "yob" and ".txt" from file name
        data$Year <- gsub( "yob|.txt", "", filename )
    
        return( data )
    }
    
    # execute that function across all files, outputting a data frame
    doMC::registerDoMC( cores = 4 )
    babynames <- plyr::ldply( .data = list.files(pattern="*.txt"),
                              .fun = readFun,
                              .parallel = TRUE )
    

    这将以简洁整洁的方式为您提供数据,这就是我建议从这里开始的方式。虽然可以将每年的数据分成单独的列,但这可能不是最好的方法。

    注意:根据您的偏好,将Year 列转换为integer 类可能是个好主意。但这取决于你。

    【讨论】:

    • 这种方式生成数据框而不是列表 - 我在将 Michael 的方法从列表转换为数据框时遇到了麻烦。但是,我将如何将新列中的年份添加到我的数据框中?有点像在 python 中追加
    • 您是否包含了@Michael Griffiths 方法的最后一行rbind?这应该可以转换为数据框。
    • 您所要求的听起来不像append,而是每个文件的新列。对于大多数数据集,这不是一个好主意。每个文件的 namegender 列是否相同?
    【解决方案3】:

    考虑lapply() 中的匿名函数:

    files = list.files(pattern="*.txt")
    
    dfList <- lapply(files, function(i) {
         df <- read.csv(i, header=FALSE, col.names=c("Name", "Gender", "Count"))
         df$Year <- gsub("yob", "", i) 
         return(df)
    })
    
    finaldf <- do.call(rbind, dflist)
    

    【讨论】:

      【解决方案4】:

      在这种情况下,for 循环可能比 lapply 更合适。

      file_list = list.files(pattern="*.txt")
      data_list <- vector("list", "length" = length(file.list))
      
      for (i in seq_along(file_list)) {
          filename = file_list[[i]]
      
          # Read data in
          df <- read.csv(filename, header = FALSE, col.names = c("Name", "Gender", "Count"))
      
          # Extract year from filename
          year = gsub("yob", "", filename)
          df[["Filename"]] = year
      
          # Add year to data_list
          data_list[[i]] <- df
      }
      
      babynames <- do.call(rbind, data_list)
      

      【讨论】:

      • 我更改了 # Extract year from filename year = gsub("yob", "", filename) df[["Filename"]] = year 手动增加年份,因为 .txt 是尾随但谢谢你的帮助!
      猜你喜欢
      • 2018-01-16
      • 1970-01-01
      • 1970-01-01
      • 2019-04-11
      • 2019-05-08
      • 1970-01-01
      • 2020-08-09
      • 1970-01-01
      • 2021-07-01
      相关资源
      最近更新 更多