【问题标题】:Read all files in a folder and apply a function to each data frame读取文件夹中的所有文件并将函数应用于每个数据框
【发布时间】:2012-03-05 09:44:05
【问题描述】:

我正在对特定文件夹中的所有文件进行一项相对简单的分析,并将其放入一个函数中。我想知道是否有人有任何提示可以帮助我在多个不同文件夹上自动执行该过程。

  1. 首先,我想知道是否有办法将特定文件夹中的所有文件直接读取到 R 中。我相信以下命令会列出所有文件:

files <- (Sys.glob("*.csv"))

...我从Using R to list all files with a specified extension找到的

然后下面的代码将所有这些文件读入 R.

listOfFiles <- lapply(files, function(x) read.table(x, header = FALSE)) 

…来自Manipulating multiple files in R

但这些文件似乎是作为一个连续列表而不是单个文件读入的……如何更改脚本以将特定文件夹中的所有 csv 文件作为单个数据帧打开?

  1. 其次,假设我可以单独读取所有文件,我如何一次完成所有这些数据帧的功能。例如,我创建了四个小数据框,以便说明我想要什么:

     Df.1 <- data.frame(A = c(5,4,7,6,8,4),B = (c(1,5,2,4,9,1)))
     Df.2 <- data.frame(A = c(1:6),B = (c(2,3,4,5,1,1)))
     Df.3 <- data.frame(A = c(4,6,8,0,1,11),B = (c(7,6,5,9,1,15)))
     Df.4 <- data.frame(A = c(4,2,6,8,1,0),B = (c(3,1,9,11,2,16)))
    

我还编了一个示例函数:

Summary<-function(dfile){
SumA<-sum(dfile$A)
MinA<-min(dfile$A)
MeanA<-mean(dfile$A)
MedianA<-median(dfile$A)
MaxA<-max(dfile$A)

sumB<-sum(dfile$B)
MinB<-min(dfile$B)
MeanB<-mean(dfile$B)
MedianB<-median(dfile$B)
MaxB<-max(dfile$B)

Sum<-c(sumA,sumB)
Min<-c(MinA,MinB)
Mean<-c(MeanA,MeanB)
Median<-c(MedianA,MedianB)
Max<-c(MaxA,MaxB)
rm(sumA,sumB,MinA,MinB,MeanA,MeanB,MedianA,MedianB,MaxA,MaxB)

Label<-c("A","B")
dfile_summary<-data.frame(Label,Sum,Min,Mean,Median,Max)
return(dfile_summary)}

我通常会使用以下命令将函数应用于每个单独的数据帧。

Df1.summary

有没有办法代替将函数应用于所有数据框,并使用汇总表中数据框的标题(即 Df1.summary)。

非常感谢,

凯蒂

【问题讨论】:

    标签: r list lapply summary


    【解决方案1】:

    相反,我确实认为使用list 可以很容易地自动化这些事情。

    这是一种解决方案(我将您的四个数据框存储在文件夹 temp/ 中)。

    filenames <- list.files("temp", pattern="*.csv", full.names=TRUE)
    ldf <- lapply(filenames, read.csv)
    res <- lapply(ldf, summary)
    names(res) <- substr(filenames, 6, 30)
    

    存储文件的完整路径很重要(就像我对full.names 所做的那样),否则您必须粘贴工作目录,例如

    filenames <- list.files("temp", pattern="*.csv")
    paste("temp", filenames, sep="/")
    

    也可以。请注意,我使用substr 提取文件名,同时丢弃完整路径。

    您可以按如下方式访问您的汇总表:

    > res$`df4.csv`
           A              B        
     Min.   :0.00   Min.   : 1.00  
     1st Qu.:1.25   1st Qu.: 2.25  
     Median :3.00   Median : 6.00  
     Mean   :3.50   Mean   : 7.00  
     3rd Qu.:5.50   3rd Qu.:10.50  
     Max.   :8.00   Max.   :16.00  
    

    如果你真的想得到单独的汇总表,你可以在之后提取它们。例如,

    for (i in 1:length(res))
      assign(paste(paste("df", i, sep=""), "summary", sep="."), res[[i]])
    

    【讨论】:

    • +1 我会plyr::llply(或ldply)而不是lapply 来保留整个名称,并定义我自己的摘要函数,例如plyr::each(min, max, mean, sd, median)
    • +1 @chl:感谢 list.files 函数中的全名技巧......我在我的回答中忘记了它!!!
    • @baptiste (+1) 感谢plyr 的建议。
    • 谢谢@chl。如何将上述代码与我编写的函数一起使用?我上面使用的示例函数(“Summary”)以及总和、平均值、中位数等只是用作我快速创建的示例 - 我用于实际分析的实际函数要复杂得多。关于如何将更复杂的函数合并到上述代码中以提供相同的单个汇总表的任何想法? ——
    • @Katie 我猜你可以用你的任何函数替换summary,前提是它需要一个 data.frame 作为参数(和/或在不同的 DF 中保持不变的可选参数)。例如,lapply(ldf, function(x) apply(x, 2, function(x) c(mean(x), sd(x)))) 将返回均值和 SD 计算 colwise。
    【解决方案2】:

    通常我不在 R 中使用 for 循环,但这是我使用 for 循环和两个包的解决方案:plyrdostats

    plyr 在 cran 上,您可以在 https://github.com/halpo/dostats 上下载 dostats(可能使用 Hadley devtools 包中的 install_github)

    假设我在 csv 文件中有你的前两个 data.frame(Df.1 和 Df.2),你可以这样做。

    require(plyr)
    require(dostats)
    
    files <- list.files(pattern = ".csv")
    
    
    for (i in seq_along(files)) {
    
        assign(paste("Df", i, sep = "."), read.csv(files[i]))
    
        assign(paste(paste("Df", i, sep = ""), "summary", sep = "."), 
               ldply(get(paste("Df", i, sep = ".")), dostats, sum, min, mean, median, max))
    
    }
    

    这是输出

    R> Df1.summary
      .id sum min   mean median max
    1   A  34   4 5.6667    5.5   8
    2   B  22   1 3.6667    3.0   9
    R> Df2.summary
      .id sum min   mean median max
    1   A  21   1 3.5000    3.5   6
    2   B  16   1 2.6667    2.5   5
    

    【讨论】:

    • (+1) 看起来我们同时回答了你的plyr 解决方案非常好!
    • 感谢@dickoa 的回答。我编写的功能(“摘要”)描述得很差。我只是将它用于说明目的-我的实际功能要复杂得多,所以我想知道如何更改上述代码(可能还有我的功能),以便将其应用于所有不同的数据帧(而不仅仅是使用 R 中的内置函数)。
    【解决方案3】:

    这是一个tidyverse 选项,它可能不是最优雅的,但在摘要中包含的内容方面提供了一些灵活性:

    library(tidyverse)
    dir_path <- '~/path/to/data/directory/'
    file_pattern <- 'Df\\.[0-9]\\.csv' # regex pattern to match the file name format
    
    read_dir <- function(dir_path, file_name){
      read_csv(paste0(dir_path, file_name)) %>% 
        mutate(file_name = file_name) %>%                # add the file name as a column              
        gather(variable, value, A:B) %>%                 # convert the data from wide to long
        group_by(file_name, variable) %>% 
        summarize(sum = sum(value, na.rm = TRUE),
                  min = min(value, na.rm = TRUE),
                  mean = mean(value, na.rm = TRUE),
                  median = median(value, na.rm = TRUE),
                  max = max(value, na.rm = TRUE))
      }
    
    df_summary <- 
      list.files(dir_path, pattern = file_pattern) %>% 
      map_df(~ read_dir(dir_path, .))
    
    df_summary
    # A tibble: 8 x 7
    # Groups:   file_name [?]
      file_name variable   sum   min  mean median   max
      <chr>     <chr>    <int> <dbl> <dbl>  <dbl> <dbl>
    1 Df.1.csv  A           34     4  5.67    5.5     8
    2 Df.1.csv  B           22     1  3.67    3       9
    3 Df.2.csv  A           21     1  3.5     3.5     6
    4 Df.2.csv  B           16     1  2.67    2.5     5
    5 Df.3.csv  A           30     0  5       5      11
    6 Df.3.csv  B           43     1  7.17    6.5    15
    7 Df.4.csv  A           21     0  3.5     3       8
    8 Df.4.csv  B           42     1  7       6      16
    

    【讨论】:

    • 非常灵活的解决方案。对于我的数据格式 read_csv() 无法正常工作,因此我将其替换为 data.table::fread()
    猜你喜欢
    • 1970-01-01
    • 2019-11-18
    • 2020-11-15
    • 2013-02-04
    • 1970-01-01
    • 1970-01-01
    • 2016-12-11
    相关资源
    最近更新 更多