【问题标题】:Loop through CSV files--issue completing task for each individual file循环浏览 CSV 文件——为每个单独的文件发出完成任务
【发布时间】:2018-03-18 12:40:21
【问题描述】:

我正在尝试遍历多个 CSV 文件并为每个文件完成相同的任务以节省自己的时间。首先,我运行“list.files”列出文件夹中的所有文件(例如 GPS_Collar33800_13.csv、GPS_Collar33801_13.CSV 等)。然后我开发了一个循环,但我正在努力研究如何构建代码的其他部分来处理每个单独的文件。我的最终目标是拥有 24 个在结构上看起来都相同的文件,然后我需要将它们全部合并到一个主文件中。另一个问题是我需要为每个文件列出一个唯一 ID(为衣领 ID 添加列,例如 33800、33801、33802 等),但我不知道如何在不手动添加新唯一的情况下轻松做到这一点手动 ID(如果我知道它首先引入了文件 GPS_Collar33800_13.csv,那么我可以使 AnimalID 列 value=33800 并对 GPS_Collar33801_13.csv 执行相同的操作并添加 AnimalID 列 value=33801)。唯一 ID 基于文件名。我们欢迎所有的建议!

 ## List CSV files in folder
`files<-list.files()`

## Run a for loop to complete the same tasks for each
for (i in 1:length(files)){
## Read table
tmp<-read.table(files[i],header=FALSE,sep=" ")
## Keep certain columns
tmp1 <- tmp[c(2:5,9,10,12,13)]
#Name the remaining columns
names(tmp1) <- 
c("GMT_Date","GMT_Time","LMT_Date","LMT_Time","Latitude","Longitude","PDOP","2D_3D")
#Add column for collar ID
tmp1$AnimalID<-33800
#Cleanup dataframe by removing records with NAs
tmp1[tmp1 == "N/A"]  <- NA
tmp2<-na.omit(tmp1)

【问题讨论】:

    标签: r loops csv


    【解决方案1】:

    你可以试试这个:

    library(stringr)
    ## List CSV files in folder
    files<-list.files()
    
    big.df <- vector('list',length(files))
    
    ## Run a for loop to complete the same tasks for each
    for (i in 1:length(files)){
      ## Read table
      tmp<-read.table(files[i],header=FALSE,sep=" ")
      ## Keep certain columns
      tmp1 <- tmp[c(2:5,9,10,12,13)]
      #Name the remaining columns
      names(tmp1) <- 
        c("GMT_Date","GMT_Time","LMT_Date","LMT_Time","Latitude","Longitude","PDOP","2D_3D")
      #Add column for collar ID
      tmp1$AnimalID<-str_match(files[i], 'Collar(\\d+)_')[,2]
      #Cleanup dataframe by removing records with NAs
      tmp1[tmp1 == "N/A"]  <- NA
      tmp2<-na.omit(tmp1)
      big.df[[i]] <- tmp2
    
    }
    final.df <- do.call('rbind', big.df)
    

    它将需要stringr 包,并假设您的文件名看起来都像“GPS_Collar33801_13.csv”等。然后它会读取每个文件,将其存储在一个大列表中,移动到下一个文件......当完成了,它将它们全部混合在一个名为 final.df 的 data.frame 中。

    编辑:刚刚修复了str_match 参数。

    【讨论】:

    • @Buck2079 很高兴听到它 :) 如果您能接受答案,将不胜感激......虽然我不是为了代表! (我是。)
    【解决方案2】:

    所以让我在开始之前确保我理解了这个问题:

    1. 对于文件夹中的每个文件,
      1. 将文件作为数据框导入
      2. 删除一些列
      3. 重命名剩余的列
      4. 将数据框中的列设置为从文件名中获取的值
      5. 删除任何地方包含字符串“N/A”的案例
    2. 然后,通过 UNION 将每个生成的数据帧合并为一个数据帧(即,将行加在一起,因为列应该相同)。

    向您的数据提供任何此类问题至关重要。如果您无法提供您的特定数据,请创建一些仍能证明手头问题的假数据。然后,提供一个示例,说明操作完成后的外观。这样可以减少回答您问题的人的猜测。

    说了这么多,让我们开始吧。

    让我们抽象出任务 #1 的子部分,假设我们有一个名为 process_a_file 的函数,它将执行每个单独文件的步骤 1-5 并返回一个数据帧。稍后我可以解释该函数的工作原理。

    对于“每个文件”部分,您需要lapplylapply 在您提供的列表的每个元素上运行给定函数,并返回函数返回的列表:

    results_list <- lapply(files, process_a_file)
    

    这将返回一个列表,其中列表的每个元素都是process_a_file 返回的数据框。然后你需要一个函数来组合它们——我推荐 bind_rows 来自包 dplyr

    results_df <- dplyr::bind_rows(results_list)
    

    这就是你需要做的!

    那么,现在,我们在process_a_file 中输入了什么?这很容易——你的代码大部分完成了,但我更喜欢一些不同的方法:)

    process_a_file <- function(filename) {
        #???????
    }
    

    第 1 步是将文件作为数据框导入。为此,我推荐 readr 包中的 read_delim - 它比默认的 R 方法快得多,具有很好的默认值,并且让我们通过指定“N/A”表示 NA 来同时处理第 5 步:

    df <- readr::read_delim(filename, delim = " ", col_names = FALSE, na = "N/A")
    

    对于第 2 步,您的方法可行,但我也推荐来自 dplyrselect 函数:

    dplyr::select(df, 2:5,9,10,12,1)
    

    您还可以使用不带引号的名称索引列,也可以删除带有 -5-column_name 的列 - 您可以同时执行第 3 步!

    df <- dplyr::select(
      df,
      GMT_Date = 2,
      GMT_Time = 3,
      LMT_Date = 4,
      LMT_Time = 5,
      Latitude = 9,
      Longitude = 10,
      PDOP = 12,
      `2D_3D` = 13
      )
    

    您重命名列的方式也很好。顺便说一句,如果你以数字开头的列名,你必须在任何地方都使用这种 `backtick` 语法,所以这很不方便,如果可以的话,你应该避免它。

    最后,我建议使用正则表达式从文件名中获取 ID。我假设您可以编写该正则表达式,因为它确实超出了范围 - 因此您可以使用 basename(tools::file_path_sans_ext(filename) 返回不带路径或扩展名的文件名,并使用 stringr::str_extract 弹出 ID,然后将其添加到使用 dplyr::mutate 的列

    dplyr::mutate(df, animal_id = stringr::str_extract(basename(tools::file_path_sans_ext(filename)), "THE REGEX GOES HERE"))
    

    所以现在,把这一切放在一起 - 使用 dplyr 的管道语法%&gt;% 让它看起来不错:

    process_a_file <- function(filename) {
      readr::read_delim(filename,
                        delim = " ",
                        col_names = FALSE,
                        na = "N/A") %>%
        dplyr::select(
          GMT_Date = 2,
          GMT_Time = 3,
          LMT_Date = 4,
          LMT_Time = 5,
          Latitude = 9,
          Longitude = 10,
          PDOP = 12,
          `2D_3D` = 13
        ) %>%
        dplyr::mutate(animal_id = stringr::str_extract(basename(tools::file_path_sans_ext(filename)), "THE REGEX GOES HERE"))
    }
    results_list <- lapply(files, process_a_file)
    results_df <- dplyr::bind_rows(results_list)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-15
      • 1970-01-01
      • 2020-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多