Baca semua file dalam folder dan terapkan fungsi ke setiap bingkai data

90

Saya melakukan analisis yang relatif sederhana yang telah saya masukkan ke dalam suatu fungsi, pada semua file dalam folder tertentu. Saya bertanya-tanya apakah ada yang punya tip untuk membantu saya mengotomatiskan proses pada sejumlah folder yang berbeda.

  1. Pertama, saya bertanya-tanya apakah ada cara membaca semua file dalam folder tertentu langsung ke R. Saya yakin perintah berikut akan mencantumkan semua file:

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

... yang saya temukan dari Using R untuk mendaftar semua file dengan ekstensi tertentu

Dan kemudian kode berikut membaca semua file itu menjadi R.

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

… Dari Memanipulasi banyak file di R

Tetapi file tampaknya dibaca sebagai satu daftar terus menerus dan bukan file individual ... bagaimana saya bisa mengubah skrip untuk membuka semua file csv dalam folder tertentu sebagai kerangka data individu?

  1. Kedua, dengan asumsi bahwa saya dapat membaca semua file secara terpisah, bagaimana cara menyelesaikan fungsi pada semua dataframe ini sekaligus. Misalnya, saya telah membuat empat kerangka data kecil sehingga saya dapat mengilustrasikan apa yang saya inginkan:

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

Saya juga membuat fungsi contoh:

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

Saya biasanya akan menggunakan perintah berikut untuk menerapkan fungsi ke setiap kerangka data individu.

Df1.summary <-Summary (dfile)

Apakah ada cara selain menerapkan fungsi ke semua dataframe, dan menggunakan judul dataframe di tabel ringkasan (mis. Df1.summary).

Terimakasih banyak,

Katie

KT_1
sumber

Jawaban:

104

Sebaliknya, menurut saya bekerja dengan listmembuatnya mudah untuk mengotomatiskan hal-hal seperti itu.

Berikut adalah satu solusi (saya menyimpan empat dataframe Anda di 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)

Penting untuk menyimpan path lengkap untuk file Anda (seperti yang saya lakukan dengan full.names), jika tidak, Anda harus menempelkan direktori kerja, mis.

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

akan bekerja juga. Perhatikan bahwa saya biasa substrmengekstrak nama file sambil membuang jalur lengkap.

Anda dapat mengakses tabel ringkasan Anda sebagai berikut:

> 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  

Jika Anda benar-benar ingin mendapatkan tabel ringkasan individual, Anda dapat mengekstraknya setelahnya. Misalnya,

for (i in 1:length(res))
  assign(paste(paste("df", i, sep=""), "summary", sep="."), res[[i]])
chl
sumber
3
+1 Saya akan plyr::llply(atau ldply) alih-alih lapplymenyimpan nama di seluruh, dan menentukan fungsi ringkasan saya sendiri, misalnyaplyr::each(min, max, mean, sd, median)
baptiste
+1 @chl: terima kasih untuk trik nama lengkap dalam fungsi list.files .... saya lupa di jawaban saya !!!
dickoa
@baptiste (+1) Terima kasih atas plyrsarannya.
chl
Terima kasih @chl. Bagaimana cara menggunakan kode di atas dengan fungsi yang telah saya tulis? Contoh fungsi yang saya gunakan di atas ("Ringkasan") dengan sum, mean, median dll. Hanya digunakan sebagai contoh yang saya buat dengan cepat - fungsi sebenarnya yang saya gunakan untuk analisis sebenarnya jauh lebih kompleks. Adakah ide tentang bagaimana saya menggabungkan fungsi yang lebih kompleks ke dalam kode di atas untuk memberikan tabel ringkasan individual yang sama? -
KT_1
@Katie Saya kira Anda dapat mengganti summarydengan fungsi apa pun milik Anda, asalkan dibutuhkan data.frame sebagai argumen (dan / atau parameter opsional yang konstan di DF perbedaan). Misalnya, lapply(ldf, function(x) apply(x, 2, function(x) c(mean(x), sd(x))))akan mengembalikan mean dan SD menghitung warna.
chl
16

biasanya saya tidak menggunakan for loop di R, tetapi berikut adalah solusi saya menggunakan for loop dan dua paket: plyr dan dostats

plyr ada di cran dan Anda dapat mengunduh dostat di https://github.com/halpo/dostats (mungkin menggunakan install_github dari paket devtools Hadley )

Dengan asumsi bahwa saya memiliki dua data.frame pertama Anda (Df.1 dan Df.2) dalam file csv, Anda dapat melakukan sesuatu seperti ini.

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

}

Ini hasilnya

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
dickoa
sumber
(+1) Sepertinya kami menjawab cukup bersamaan dan plyrsolusi Anda cukup bagus!
chl
1
Terima kasih @dickoa atas jawaban Anda. Fungsi yang saya buat ("Ringkasan") tidak dijelaskan dengan baik. Saya baru saja menggunakannya untuk tujuan ilustrasi - fungsi sebenarnya saya jauh lebih rumit jadi saya bertanya-tanya bagaimana kode di atas (dan mungkin fungsi saya) dapat diubah sehingga diterapkan untuk semua bingkai data yang berbeda (dan tidak hanya gunakan fungsi bawaan di R).
KT_1
2

Berikut adalah tidyverseopsi yang mungkin bukan yang paling elegan, tetapi menawarkan beberapa fleksibilitas dalam hal apa yang disertakan dalam ringkasan:

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
sbha
sumber
Solusi hebat karena sangat fleksibel. Karena format data saya read_csv()tidak berfungsi dengan baik jadi saya menggantinya dengan data.table::fread().
Thorsten