【问题标题】:Using a loop to process and format multiple .csv files使用循环处理和格式化多个 .csv 文件
【发布时间】:2018-07-31 13:12:09
【问题描述】:

我有一堆 csv 文件正在读入 R。

以下示例数据可帮助您进行此调查。

ABC_H <- structure(list(Name = c("Jim Smith", "John Doe"), user_id = c(23L, 25L), sales = c(300L, 140L), shape = c(6L, 200L), size = c(402L, 305L)),row.names= c(NA, -2L), class = c("tbl_df", "tbl", "data.frame"), spec = structure(list(cols = list(Name = structure(list(), class = c("collector_character", "collector")), user_id = structure(list(), class = c("collector_integer", "collector")), sales = structure(list(), class = c("collector_integer", "collector")), shape = structure(list(), class = c("collector_integer", "collector")), size = structure(list(), class = c("collector_integer", "collector"))), default = structure(list(), class = c("collector_guess", "collector"))), class = "col_spec"))
BCD_H <- structure(list(Name = c("Jim Smith", "John Doe"), user_id = c(23L, 25L), sales = c(190L, 120L), shape = c(10L, 5L), size = c(500L, 200L)), row.names = c(NA, -2L), class = c("tbl_df", "tbl", "data.frame"), spec =structure(list(cols = list(Name = structure(list(), class = c("collector_character", "collector")), user_id = structure(list(), class = c("collector_integer", "collector")), sales = structure(list(), class = c("collector_integer", "collector")), shape = structure(list(), class = c("collector_integer", "collector")), size = structure(list(), class = c("collector_integer", "collector"))), default = structure(list(), class = c("collector_guess", "collector"))), class = "col_spec"))
XYZ_H <- structure(list(Name = c("Jim Smith", "John Doe"), user_id = c(23L, 25L), sales = c(190L, 120L), shape = c(10L, 5L), size = c(500L, 200L)), row.names = c(NA, -2L), class = c("tbl_df", "tbl", "data.frame"), spec =structure(list(cols = list(Name = structure(list(), class = c("collector_character", "collector")), user_id = structure(list(), class = c("collector_integer", "collector")), sales = structure(list(), class = c("collector_integer", "collector")), shape = structure(list(), class = c("collector_integer", "collector")), size = structure(list(), class = c("collector_integer", "collector"))), default = structure(list(), class = c("collector_guess", "collector"))), class = "col_spec"))

ABC_P <- structure(list(Name = c("Alex Smith", "John Curry"), user_id = c(102L, 433L), color = c(164L, 153L), number = c(20L, 3L), scale = c(6L, 1L)), row.names = c(NA, -2L), class = c("tbl_df", "tbl", "data.frame"), spec = structure(list(cols = list(Name = structure(list(), class = c("collector_character", "collector")), user_id = structure(list(), class = c("collector_integer", "collector")), color = structure(list(), class = c("collector_integer", "collector")), number = structure(list(), class = c("collector_integer", "collector")), scale = structure(list(), class = c("collector_integer", "collector"))), default = structure(list(), class = c("collector_guess", "collector"))), class = "col_spec"))
BCD_P <- structure(list(Name = c("Alex Smith", "John Curry"), user_id = c(102L, 433L), color = c(300L, 200L), number = c(100L, 4L), scale = c(2L, 5L)), row.names = c(NA, -2L), class = c("tbl_df", "tbl", "data.frame"), spec = structure(list(cols = list(Name = structure(list(), class = c("collector_character", "collector")), user_id = structure(list(), class = c("collector_integer", "collector")), color = structure(list(), class = c("collector_integer", "collector")), number = structure(list(), class = c("collector_integer", "collector")), scale = structure(list(), class = c("collector_integer", "collector"))), default = structure(list(), class = c("collector_guess", "collector"))), class = "col_spec"))
XYZ_P <- structure(list(Name = c("Alex Smith", "John Curry"), user_id = c(102L, 433L), color = c(300L, 200L), number = c(100L, 4L), scale = c(2L, 5L)), row.names = c(NA, -2L), class = c("tbl_df", "tbl", "data.frame"), spec = structure(list(cols = list(Name = structure(list(), class = c("collector_character", "collector")), user_id = structure(list(), class = c("collector_integer", "collector")), color = structure(list(), class = c("collector_integer", "collector")), number = structure(list(), class = c("collector_integer", "collector")), scale = structure(list(), class = c("collector_integer", "collector"))), default = structure(list(), class = c("collector_guess", "collector"))), class = "col_spec"))   

我使用的命名约定是基于文件名的。

这是我目前用来加载 .csv 文件的手动代码示例。还有其他几个 csv 文件。工作目录加载在脚本的顶部。

ABC_H <- read_csv(file.path(getwd(), "input_data","ABC_H_2018.csv"))
ABC_P <- read_csv(file.path(getwd(), "input_data","ABC_P_2018.csv"))
BCD_H <- read_csv(file.path(getwd(), "input_data","BCD_H_2018.csv"))
BCD_P <- read_csv(file.path(getwd(), "input_data","BCD_P_2018.csv"))
XYZ_H <- read_csv(file.path(getwd(), "input_data","XYZ_H_2018.csv"))
XYZ_P <- read_csv(file.path(getwd(), "input_data","XYZ_P_2018.csv"))

然后我使用 dplyr 单独格式化每个文件。所有包含后缀“H”的文件都将使用相同的列进行格式化,所有包含“P”的文件将使用相同的列进行格式化。这是我的前 2 个带后缀“H”的 dplyr 代码示例。

ABC_H_formatted <- ABC_H %>%
mutate(data_source = "ABC")%>%
rename(user_id = user)%>%
select(user_id, Name, data_source, size, shape, sales)

BCD_H_formatted <- BCD_H %>%
mutate(data_source = "BCD")%>%
rename(user_id = user)%>%
select(user_id, Name, data_source, size, shape, sales)


XYZ_H_formatted <- BCD_H %>%
mutate(data_source = "BCD")%>%
rename(user_id = user)%>%
select(user_id, Name, data_source, size, shape, sales)

ABC_P_formatted <- ABC_P %>%
mutate(data_source = "ABC")%>%
rename(user_id = user)%>%
select(user_id, Name, data_source, color, number, scale)

BCD_P_formatted <- BCD_P %>%
mutate(data_source = "BCD")%>%
rename(user_id = user)%>%
select(user_id, Name, data_source, color, number, scale)

XYZ_P_formatted <- XYZ_P %>%
mutate(data_source = "XYZ")%>%
rename(user_id = user)%>%
select(user_id, Name, data_source, color, number, scale)

这就是我想做的事情。

  1. 创建 2 个循环,一个用于所有带有 _H 后缀的文件,一个用于所有带有 _P 后缀的文件
  2. 根据文件名创建data_source列(如上)
  3. 为每个文件选择上面列出的列
  4. 为所有 _H 创建一个 data.frame,为 _P 创建一个

提前致谢!

【问题讨论】:

    标签: r loops dplyr lapply


    【解决方案1】:

    这是您真正想到编写自定义函数来执行您想要的操作,然后将该函数应用于对象列表的地方。这是 R 中典型的迭代方式。

    既然您已经在使用dplyr,我将展示一个tidyverse 方法(不过这也可以在base R 中轻松完成)。创建一个执行您想要的处理步骤的函数,并分配一个后缀和 data_source 列(从文件名中提取一些正则表达式和stringr)。

    然后,您将希望从目录中获取文件列表,使用匹配模式获取所有文件,而不是手动输入每个文件。

    最后,我们使用purrr 中的map_dfread_data 函数“映射”到列表中的每个文件,然后将所有结果绑定到一个数据框中。这不会产生您希望的两个数据框,但使用 suffix 列,您可以轻松地对每个部分进行子集化。

    您可能会遇到一些错误,因为我没有您的数据来对此进行测试。将来,最好为您的问题制作一个可重现的示例,以便我们可以更好地帮助您!

    library(tidyverse) #dplyr, purrr, stringr, readr
    
    read_data <- function(file) {
    
      name <- basename(file)
    
      suffix <- str_extract(name, "(?<=_)[HP]")
    
      data_source <- str_extact(name, "[A-Z]+(?=_)")
    
      if (suffix == "P") {
        cols <- c("suffix", "user_id", "Name", "data_source", "color", "number", "scale")
      } 
    
      if (suffix == "H") {
        cols <- c("suffix", "user_id", "Name", "data_source", "size", "shape", "sales")
      }
    
      read_csv(file) %>% 
        rename(user_id = user) %>% 
        mutate(datar_source = data_source,
               suffix = suffix) %>% 
        select(one_of(cols))
    
    }
    files <- dir(file.path(getwd(), "input_data"), pattern = "ABC|BCD", full.names = TRUE)
    
    result <- map_df(files, read_data)
    

    【讨论】:

    • 谢谢杰克。我添加了一个可重现的示例,希望能帮助我在这个问题上提供更具体的指导。在这种情况下,我添加了第三个数据集(XYZ)。 _H 和 _P 文件各有 6 个文件。有没有办法根据上面的例子改变上面的函数,并且知道每个都有几个数据集?
    • 是的,您可以使用上面的示例并构建您需要的逻辑。这将是 suffix 周围的 if-else 块,它将您想要的列传递给 select
    • 抱歉,我对 r 比较陌生,不明白如何为 12 个不同的 csv 文件(_H 和 _P 各 6 个)构建 if/else 块。能不能多给点指导?谢谢!
    • 更新了我的答案。这将为您提供两个组合的大数据框,列名中的 NA 值不是通过前缀选择的。您可以从那里对其进行子集处理,并相应地提取出两个数据名
    • 谢谢杰克。我使用了我的样本数据,结果框架给了我 0 个结果。看来文件对象是空的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-04
    • 2021-04-10
    • 1970-01-01
    • 2021-03-16
    • 2016-08-21
    • 1970-01-01
    相关资源
    最近更新 更多