Leia todos os arquivos em uma pasta e aplique uma função a cada quadro de dados


90

Estou fazendo uma análise relativamente simples que coloquei em uma função, em todos os arquivos em uma pasta específica. Eu queria saber se alguém tem alguma dica para me ajudar a automatizar o processo em várias pastas diferentes.

  1. Em primeiro lugar, gostaria de saber se existe uma maneira de ler todos os arquivos em uma pasta específica diretamente para R. Acredito que o seguinte comando listará todos os arquivos:

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

... que encontrei em Using R para listar todos os arquivos com uma extensão especificada

E então o código a seguir lê todos esses arquivos em R.

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

… De manipular vários arquivos em R

Mas os arquivos parecem ser lidos como uma lista contínua e não como arquivos individuais ... como posso alterar o script para abrir todos os arquivos csv em uma pasta específica como dataframes individuais?

  1. Em segundo lugar, supondo que eu possa ler todos os arquivos separadamente, como faço para completar uma função em todos esses dataframes de uma vez. Por exemplo, criei quatro pequenos dataframes para ilustrar o que desejo:

    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)))

Também criei uma função de exemplo:

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)}

Normalmente, eu usaria o seguinte comando para aplicar a função a cada dataframe individual.

Df1.summary <-Summary (dfile)

Existe uma maneira em vez de aplicar a função a todos os dataframes, e usar os títulos dos dataframes nas tabelas de resumo (ou seja, Df1.summary).

Muito Obrigado,

Katie

Respostas:


104

Pelo contrário, acho que trabalhar com listtorna mais fácil automatizar essas coisas.

Aqui está uma solução (eu armazenei seus quatro dataframes na pasta 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)

É importante armazenar o caminho completo para seus arquivos (como fiz com full.names), caso contrário, você terá que colar o diretório de trabalho, por exemplo

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

vai funcionar também. Observe que eu costumava substrextrair nomes de arquivos enquanto descartava o caminho completo.

Você pode acessar suas tabelas de resumo da seguinte forma:

> 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  

Se você realmente deseja obter tabelas de resumo individuais, pode extraí-las posteriormente. Por exemplo,

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

3
+1 Eu faria plyr::llply(ou ldply) em vez de lapplypreservar os nomes por completo e definir minha própria função de resumo, por exemploplyr::each(min, max, mean, sd, median)
baptiste

+1 @chl: obrigado pelo truque de fullnames na função list.files .... esqueci na minha resposta !!!
dickoa

@baptiste (+1) Obrigado pela plyrsugestão.
chl

Obrigado @chl. Como uso o código acima com uma função que escrevi? A função de exemplo que usei acima ("Resumo") com soma, média, mediana etc. foi usada apenas como um exemplo que criei rapidamente - a função real que estou usando para minha análise real é muito mais complexa. Alguma ideia de como incorporar uma função mais complexa ao código acima para fornecer as mesmas tabelas de resumo individuais? -
KT_1

@Katie Eu acho que você pode substituir summarypor qualquer função sua, desde que receba um data.frame como um argumento (e / ou parâmetros opcionais que são constantes nas diferenças de DFs). Por exemplo, lapply(ldf, function(x) apply(x, 2, function(x) c(mean(x), sd(x))))retornaria a média e o SD calculado simultaneamente.
chl

16

normalmente eu não uso for loop em R, mas aqui está minha solução usando for loops e dois pacotes: plyr e dostats

plyr está no cran e você pode baixar dostats em https://github.com/halpo/dostats (pode estar usando install_github do Hadley devtools pacote )

Supondo que eu tenha seus dois primeiros data.frame (Df.1 e Df.2) em arquivos csv, você pode fazer algo assim.

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))

}

Aqui está o resultado

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) Parece que respondemos bastante ao mesmo tempo e sua plyrsolução é bastante boa!
chl

1
Obrigado @dickoa por suas respostas. A função que criei ("Resumo") foi mal descrita. Eu estava usando apenas para fins ilustrativos - minha função real é muito mais complicada, então eu queria saber como o código acima (e provavelmente minha função) poderia ser alterado para que seja aplicado a todos os diferentes quadros de dados (e não apenas usar as funções integradas em R).
KT_1

1

Aqui está uma tidyverseopção que pode não ser a mais elegante, mas oferece alguma flexibilidade em termos do que está incluído no resumo:

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.