读取文件夹中的所有文件,并对每个数据框应用功能


90

我正在对一个特定文件夹中的所有文件进行一个相对简单的分析,并将其放入函数中。我想知道是否有人提供了一些技巧来帮助我在许多不同的文件夹上自动化该过程。

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

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

...我从使用R找到列出具有指定扩展名的所有文件

然后以下代码将所有这些文件读入R。

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

…从在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 <-Summary(dfile)

有没有一种方法可以将功能应用于所有数据框,而不必使用汇总表中数据框的标题(即Df1.summary)。

非常感谢,

凯蒂

Answers:


104

相反,我确实认为与之合作可以list使这些事情自动化。

这是一种解决方案(我将您的四个数据帧存储在folder中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]])

3
1,我会plyr::llply(或ldply),而不是lapply保存整个名称和定义自己的聚合功能,例如plyr::each(min, max, mean, sd, median)
巴蒂斯特

+1 @chl:感谢list.files函数中的全名技巧....我在回答中忘记了它!
dickoa 2012年

@baptiste(+1)感谢您的plyr建议。
chl 2012年

谢谢@chl。如何将上面的代码与我编写的函数一起使用?我上面使用的带有和,均值,中位数等的示例函数(“摘要”)仅用作我快速创建的示例-我用于实际分析的实际函数要复杂得多。关于如何将更复杂的函数合并到上述代码中以给出相同的单个摘要表的任何想法?–
KT_1 2012年

@Katie我猜您可以用您的summary任何函数替换,只要它以data.frame作为参数(和/或在不同DF上恒定的可选参数)即可。例如,lapply(ldf, function(x) apply(x, 2, function(x) c(mean(x), sd(x))))将返回均值并按逐级计算SD。
chl 2012年

16

通常我在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解决方案也很不错!
chl 2012年

1
感谢@dickoa的回答。我编写的功能(“摘要”)描述得很差。我只是出于说明目的使用它-我的实际函数要复杂得多,所以我想知道如何更改上述代码(可能还有我的函数),以便将其应用于所有不同的数据帧(而不仅仅是使用R中的内置函数)。
KT_1 2012年

2

这是一个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()
托尔斯滕
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.