【问题标题】:Loop over several excel files to create different dataframes, perform group by and save as a single df in R循环几个excel文件以创建不同的数据框,在R中执行分组并保存为单个df
【发布时间】:2021-03-21 20:32:15
【问题描述】:

我是 R 的新手,我有一个疑问,以防你能提供帮助。

我在一个文件夹中有多个 excel 文件。它们属于不同的子孙,但结构相同。
我想遍历它们,作为数据框加载到 R 中,执行分组并将所有内容保存在单个数据框中并导出为单个文件。这可能吗?

通过查看这里的几个答案,我做到了:

# Load the data as different dataframes

library(tidyverse)
library(readxl)

f <- list.files(pattern="xlsx")

myfiles = lapply(f, read_excel)


for (i in 1:length(f)) assign(f[i], read_excel(f[i], sheet = "Deutsch", skip=7), data.frame(f[i]))

我将它们保存为单个数据框,我不知道如何一起访问它们,所以我手动创建了一个列表:

list_df = list(filialAA.xlsx, filialAB.xlsx,filianAC.xlsx,filianAD.xlsx,filianAE.xlsx...etc)

然后我创建了一个 group by 来执行一些计算:

for (i in 1:length(list_df))
{
  list_df[i] %>% 
    group_by(ABC) %>% 
    summarise(`Revenue in EUR` = sum(`Revenue in EUR`),
              `Weight in KG` = sum(`Weight in KG`),
              `Number of Materials` = length(`Materials`),
              `Avg of deliveries` = mean(`Deliveries`))
}

如果我对每个数据帧都这样做,它会起作用。但在这个循环中它没有。 你能帮我遍历所有数据帧,执行这个分组并聚集在一个文件中吗?有可能吗?

非常感谢您的关注!

编辑:包含一个虚拟数据样本:

> dput(df1)

structure(list(Materials = c("11575358", "75378378", "21333333", 
"02469984", "05465478", "05645648"), Deliveries = c(8, 1, 12, 
5, 1, 1), ABC = c("C", "A", "C", "B", "C", "C"), `Revenue in EUR` = c(6179, 
1804802.46, 3768.04, 9e+05, 1597.5, 1544.55), `Weight in KG` = c(16.6, 
4.695625, 19, 9.14625, 2.74041666666667, 1.44208333333333)), row.names = c(NA, 
-6L), class = c("tbl_df", "tbl", "data.frame"))

> dput(df2)

structure(list(Materials = c("48654798", "05465489", "04598496", 
"08789453", "01589494", "06459849", "54694985", "65498848"), 
    Deliveries = c(24, 6, 32, 3, 11, 30, 45, 2), ABC = c("C", 
    "B", "C", "B", "C", "A", "A", "C"), `Revenue in EUR` = c(5509, 
    506978, 3978.04, 7e+05, 1597.5, 1200258, 2406975, 4059), 
    `Weight in KG` = c(29.6, 19, 24, 9.14625, 2.74041666666667, 
    50, 60, 10)), row.names = c(NA, -8L), class = c("tbl_df", 
"tbl", "data.frame"))

原始的 excel 是 xlsx 格式,有 5000 到 15000 行,大约 20 个特征,7 个选项卡。有 22 个 excel 文件需要循环。

【问题讨论】:

    标签: r excel dataframe


    【解决方案1】:

    好的,由于我没有您的文件,它可能会出现一些错误,但请尝试以下操作:

    # first of, write down your files in xlsx. I use xlsx because I prefere it
    #but you should already have them
    xlsx::write.xlsx2(df1,"df1.xlsx")
    xlsx::write.xlsx2(df1,"df2.xlsx")
    
    library(tidyverse)
    library(readxl)
    
    # here you get all the xlsx files
    f <- list.files(pattern="xlsx")  
    f
    [1] "df1.xlsx" "df2.xlsx"
    
    # an empty list
    listed <- list()
    # loop that populate the empty list with your files
    for (i in f) { 
      listed[[i]] <- read_excel(i, sheet = "Sheet1" # , skip = 7  
                                )
      print(paste0("read the", i," file")) # here it says what it's doing
    }
    
     listed
    $df1.xlsx
    # A tibble: 6 x 6
      ...1  Materials Deliveries ABC   `Revenue in EUR` `Weight in KG`
      <chr> <chr>          <dbl> <chr>            <dbl>          <dbl>
    1 1     11575358           8 C                6179           16.6 
    2 2     75378378           1 A             1804802.           4.70
    3 3     21333333          12 C                3768.          19   
    4 4     02469984           5 B              900000            9.15
    5 5     05465478           1 C                1598.           2.74
    6 6     05645648           1 C                1545.           1.44
    
    $df2.xlsx
    # A tibble: 6 x 6
      ...1  Materials Deliveries ABC   `Revenue in EUR` `Weight in KG`
      <chr> <chr>          <dbl> <chr>            <dbl>          <dbl>
    1 1     11575358           8 C                6179           16.6 
    2 2     75378378           1 A             1804802.           4.70
    3 3     21333333          12 C                3768.          19   
    4 4     02469984           5 B              900000            9.15
    5 5     05465478           1 C                1598.           2.74
    6 6     05645648           1 C                1545.           1.44
    
    # now lapply to each element of the list, the summary, creating a new list
    list_result <- lapply(listed, function(x) x %>% 
                                              group_by(ABC) %>% 
                                              summarise(
                              `Revenue in EUR` = sum(`Revenue in EUR`),
                              `Weight in KG` = sum(`Weight in KG`),
                              `Number of Materials` = length(`Materials`),
                              `Avg of deliveries` = mean(`Deliveries`)))
    
    # put the result in a data.frame  
    do.call(rbind,list_result)
    # A tibble: 6 x 5
      ABC   `Revenue in EUR` `Weight in KG` `Number of Materials` `Avg of deliveries`
    * <chr>            <dbl>          <dbl>                 <int>               <dbl>
    1 A             1804802.           4.70                     1                 1  
    2 B              900000            9.15                     1                 5  
    3 C               13089.          39.8                      4                 5.5
    4 A             1804802.           4.70                     1                 1  
    5 B              900000            9.15                     1                 5  
    6 C               13089.          39.8                      4                 5.5
    

    【讨论】:

    • @jessirocha 答案之一对您有帮助还是您需要进一步解释?
    • 嗨@s__。感谢您的回答。我得到两个答案的错误,我不知道如何解决它。所以我都是手动做的。根据您的回答,问题在于 Group_by 方法“ Fehler in UseMethod("group_by") : nicht anwendbare Methode für 'group_by' auf Objekt der Klasse "character" angewendet" 。我在某些地方读到可能安装 dplyr 会有所帮助,所以我这样做了,但错误仍然存​​在......当我发布这个问题并且它正在工作时,我也使用了 group_by,所以我不确定现在的问题是什么
    • 如果您分享您的 xlsx 之一的摘录(导入一个,执行 dput(head(file)))并将结果发布在您的问题中,我可以模仿您的数据并提供更好的回答。
    • 我创建了一个虚拟样本文件。我不允许分享原始的,但我尽量保持格式。非常感谢您的帮助!
    • @jessirocha 谢谢,但不幸的是不建议共享文件下载,我们是陌生人,这对我们的电脑可能不安全。我建议您简单地创建一个虚拟 data.frame 作为您的 xlsx 并在此处发布一个 dput(head(your_df)) 。我们将根据您的数据为自己创建一些假的 .xlsx(重要的是 colnames 相同)。另外,您需要从多个 .xlsx 中获取多个工作表吗?
    【解决方案2】:

    你也可以适当地使用purrr::map

    map_dfr(list_df, ~(. %>% 
        group_by(ABC) %>% 
        summarise(`Revenue in EUR` = sum(`Revenue in EUR`),
                  `Weight in KG` = sum(`Weight in KG`),
                  `Number of Materials` = length(`Materials`),
                  `Avg of deliveries` = mean(`Deliveries`))))
    

    它会同时rbind结果。

    即使在myfiles 中存储文件后,您也可以使用以下语法

    
    library(janitor)
    map_dfr(myfiles, ~(.[-c(1:5),] %>% row_to_names(1) %>% 
                         group_by(ABC) %>% 
                         summarise(`Revenue in EUR` = sum(as.numeric(`Revenue in EUR`)),
                                   `Weight in KG` = sum(as.numeric(`Weight in KG`)),
                                   `Number of Materials` = length(`Materials`),
                                   `Avg of deliveries` = mean(as.numeric(`Deliveries`)))
                       %>% ungroup()))
    
    

    给定文件的结果

    # A tibble: 6 x 5
      ABC   `Revenue in EUR` `Weight in KG` `Number of Materials` `Avg of deliveries`
      <chr>            <dbl>          <dbl>                 <int>               <dbl>
    1 A             1804802.           4.70                     1                 1  
    2 B              900000            9.15                     1                 5  
    3 C               13089.          39.8                      4                 5.5
    4 A             3607233          110                        2                37.5
    5 B             1206978           28.1                      2                 4.5
    6 C               15144.          66.3                      4                17.2
    

    【讨论】:

    • 感谢您的帮助!第一个解决方案总是抱怨不是向量。 Fehler:tibble 中的所有列都必须是向量。 x 列 filianAA.xlsx 是一个 fseq/function 对象。第二个解决方案适用于我的虚拟数据集,但在我的真实数据集中运行“Fehler:必须按在.data 中找到的变量分组。* 未找到ABC 列。”。这很奇怪,因为我的专栏在那里......
    • 在这种情况下,您应该检查myfiles。你能上传一个快照它的结构吗?实际上,当我们要操作的列表处于与预期不同的级别时,该方法在场景中有所不同。
    【解决方案3】:

    我喜欢编写函数,所以我会这样做(虽然它会创建一个更稳定的环境来在需要时进行修改/调试)。

    # Main Function
    main_function <- function(import, name){
     main_function.create_path() -> path
     main_function.create_output() -> output
     for(file in list.files(path){
      if(!str_detect(file, 'csv')){
       next
      }
      read_excel(file, sheet = "Deutsch", skip = 7) -> data
      main_function.calculate_values(data) -> data.values
      main_function.append_values(file, data, data.values, output) -> output
     }
     main_function.export(path, output, name)
     if(import){
      assign('values', output, envir = .Globalenv)
     }
    }
        
    # Functions
    main_function.export <- function(path, output, name){
     write.csv(output, file = paste0(path, name, '.csv'))
     }
     
    main_function.append_values <- function(file, data, data.values,   output){
     # This will create a row in the output file with the name of the file
     # without the .csv at the end in the first column and put in the 
     # calculated data in the other columns
     str_extract(file, ".+(?=.csv)") -> output[nrow(output) + 1, 'file'] 
     for(col in colnames(data.values)){
       data.values[,col] -> output[nrow(output), col]
     return(output)
     }
    
    main_function.calculate_values <- function(data){
     data %>% group_by(ABC) %>%
      summarize(`Revenue in EUR` = sum(`Revenue in Eur`, na.rm=TRUE),
                ....) -> data
     return(data)
     }
     
    main_function.create_path <- function(){
     '<path to files>' -> path
     return(path) 
     }
       
    main_function.create_output <- function(){
     data.frame('file' = as.character(NA), 'Revenue in EUR' = 0, 
      'Weight in KG' = 0, 'Number of Materials' = 0, 'Avg of deliveries' = 0) -> output
     return(output)
     }
    

    这将创建main_function,调用该main_function时将循环遍历给定路径中列出的所有文件并读取它,处理它,将其保存到output,该output将保存在与名称相同的路径中你给它。 如果您将import 设置为 TRUE,它也会保存输出

    【讨论】:

      猜你喜欢
      • 2022-01-04
      • 1970-01-01
      • 1970-01-01
      • 2020-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多