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

时间:2017-09-19 11:54:06

标签: r lapply

我在多个目录中有许多csv文件,我想要读入R tribble或data.table。我使用“list.files()”将递归参数设置为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()为每个文件运行。

6 个答案:

答案 0 :(得分: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 :(得分:2)

您可以在此使用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,则可以使用imapmap2包含索引

答案 2 :(得分:2)

tidyverse提供了一种雄辩的解决方案。我喜欢使用完整的文件路径作为文件名(如果需要,以后可以将其截断)。

加载.csv文件的示例:

library(tidyverse); library(fs)

指定文件路径

data_dir <- path("file/directory")
data_list = fs::dir_ls(data_dir, regexp = "\\.csv$")

读取数据

my_data = data_list %>% 
  purrr::map_dfr(read_csv, .id = "source")

重命名变量

my_data_renamed <- my_data %>% 
  dplyr::mutate(source = stringr::str_replace(source, "text-to-replace", "new-text"))
#where source is the renamed file-source column      

答案 3 :(得分:1)

在组合之前,您只需要编写自己的函数来读取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()

答案 4 :(得分:0)

您可以根据&#34;网站&#34;构建文件名向量。与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)

答案 5 :(得分:0)

data.table方法:

如果为列表命名,则在将列表绑定在一起时可以使用此名称添加到data.table中。

工作流程

files <- list.files( whatever... )
#read the files from the list
l <- lapply( files, fread )
#names the list using the basename from `l`
# this also is the step to manipuly the filesnamaes to whatever you like
names(l) <- basename( l )
#bind the rows from the list togetgher, putting the filenames into the colum "id"
dt <- rbindlist( dt.list, idcol = "id" )