首页 文章

在读取和绑定多个文件时,将“filename”列添加到表中

提问于
浏览
5

我在多个目录中有许多csv文件,我想读入R tribble或data.table . 我使用“list.files()”并将recursive参数设置为TRUE来创建文件名和路径列表,然后使用“lapply()”读取多个csv文件,然后“bind_rows()”将它们全部粘在一起一起:

filenames <- list.files(path, full.names = TRUE, pattern = fileptrn, recursive = TRUE)
tbl <- lapply(filenames, read_csv) %>% 
  bind_rows()

这种方法很好 . 但是,我需要从每个文件名中提取一个子字符串,并将其作为列添加到最终表中 . 我可以使用“str_extract()”获取我需要的子字符串,如下所示:

sites <- str_extract(filenames, "[A-Z]{2}-[A-Za-z0-9]{3}")

然而,我被困在如何将提取的子字符串添加为列,因为lapply()通过read_csv()为每个文件运行 .

4 回答

  • 5

    我通常使用以下方法,基于dplyr / tidyr:

    data = tibble(File = files) %>%
        extract(File, "Site", "([A-Z]{2}-[A-Za-z0-9]{3})", remove = FALSE) %>%
        mutate(Data = lapply(File, read_csv)) %>%
        unnest(Data) %>%
        select(-File)
    
  • 1

    你可以在这里使用 purrr::map2 ,它与mapply类似

    filenames <- list.files(path, full.names = TRUE, pattern = fileptrn, recursive = TRUE)
    sites <- str_extract(filenames, "[A-Z]{2}-[A-Za-z0-9]{3}")  # same length as filenames
    
    library(purrr)
    library(dplyr)
    library(readr)
    stopifnot(length(filenames)==length(sites))  # returns error if not the same length
    ans <- map2(filenames, sites, ~read_csv(.x) %>% mutate(id = .y))  # .x is element in filenames, and .y is element in sites
    

    map2 的输出是一个列表,类似于 lapply

    如果您的开发版本为 purrr ,则可以使用 imap ,它是带有索引的 map2 的包装器

  • 2

    在组合它们之前,您只需编写自己的函数来读取csv并添加所需的列 .

    my_read_csv <- function(x) {
      out <- read_csv(x)
      site <- str_extract(x, "[A-Z]{2}-[A-Za-z0-9]{3}")
      cbind(Site=site, out)
    }
    
    filenames <- list.files(path, full.names = TRUE, pattern = fileptrn, recursive = TRUE)
    tbl <- lapply(filenames, my_read_csv) %>% bind_rows()
    
  • 0

    您可以基于“站点”构建文件名向量,其长度与tbl完全相同,然后使用cbind组合两者

    ### Get file names
    filenames <- list.files(path, full.names = TRUE, pattern = fileptrn, recursive = TRUE)
    sites <- str_extract(filenames, "[A-Z]{2}-[A-Za-z0-9]{3}")
    
    ### Get length of each csv
    file_lengths <- unlist(lapply(lapply(filenames, read_csv), nrow))
    
    ### Repeat sites using lengths
    file_names <- rep(sites,file_lengths))
    
    ### Create table
    tbl <- lapply(filenames, read_csv) %>% 
      bind_rows()
    
    ### Combine file_names and tbl
    tbl <- cbind(tbl, filename = file_names)
    

相关问题