Đọc tất cả các tệp trong một thư mục và áp dụng một chức năng cho từng khung dữ liệu


90

Tôi đang thực hiện một phần phân tích tương đối đơn giản mà tôi đã đưa vào một hàm, trên tất cả các tệp trong một thư mục cụ thể. Tôi tự hỏi liệu có ai có bất kỳ mẹo nào để giúp tôi tự động hóa quy trình trên một số thư mục khác nhau không.

  1. Đầu tiên, tôi đã tự hỏi liệu có cách nào để đọc tất cả các tệp trong một thư mục cụ thể thẳng vào R. Tôi tin rằng lệnh sau sẽ liệt kê tất cả các tệp:

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

... mà tôi tìm thấy từ Sử dụng R để liệt kê tất cả các tệp có phần mở rộng được chỉ định

Và sau đó đoạn mã sau đọc tất cả các tệp đó thành R.

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

… Từ Thao tác nhiều tệp trong R

Nhưng các tệp dường như được đọc dưới dạng một danh sách liên tục chứ không phải các tệp riêng lẻ… làm cách nào tôi có thể thay đổi tập lệnh để mở tất cả các tệp csv trong một thư mục cụ thể dưới dạng khung dữ liệu riêng lẻ?

  1. Thứ hai, giả sử rằng tôi có thể đọc tất cả các tệp một cách riêng biệt, làm cách nào để hoàn thành một chức năng trên tất cả các khung dữ liệu này trong một lần. Ví dụ: tôi đã tạo bốn khung dữ liệu nhỏ để tôi có thể minh họa những gì tôi muốn:

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

Tôi cũng đã tạo một hàm ví dụ:

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

Thông thường tôi sẽ sử dụng lệnh sau để áp dụng chức năng cho từng khung dữ liệu riêng lẻ.

Df1.summary <-Summary (dfile)

Có cách nào thay vì áp dụng hàm cho tất cả các khung dữ liệu và sử dụng tiêu đề của các khung dữ liệu trong các bảng tóm tắt (tức là Df1.summary).

Cảm ơn nhiều,

Katie

Câu trả lời:


104

Ngược lại, tôi nghĩ rằng làm việc với listnó giúp dễ dàng tự động hóa những thứ như vậy.

Đây là một giải pháp (tôi đã lưu trữ bốn khung dữ liệu của bạn trong thư mục 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)

Điều quan trọng là phải lưu trữ đường dẫn đầy đủ cho các tệp của bạn (như tôi đã làm với full.names), nếu không bạn phải dán thư mục làm việc, ví dụ:

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

cũng sẽ hoạt động. Lưu ý rằng tôi đã sử dụng substrđể trích xuất tên tệp trong khi loại bỏ đường dẫn đầy đủ.

Bạn có thể truy cập các bảng tóm tắt của mình như sau:

> 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  

Nếu bạn thực sự muốn nhận các bảng tóm tắt riêng lẻ, bạn có thể trích xuất chúng sau đó. Ví dụ,

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

3
+1 Tôi sẽ plyr::llply(hoặc ldply) thay vì lapplygiữ nguyên các tên trong suốt và xác định chức năng tóm tắt của riêng mình, ví dụplyr::each(min, max, mean, sd, median)
baptiste

+1 @chl: cảm ơn vì thủ thuật đặt tên đầy đủ trong hàm list.files .... tôi đã quên nó trong câu trả lời của mình !!!
dickoa

@baptiste (+1) Cảm ơn bạn đã plyrđề xuất.
chl

Cảm ơn @chl. Làm cách nào để sử dụng đoạn mã trên với một hàm mà tôi đã viết? Hàm ví dụ mà tôi đã sử dụng ở trên ("Tóm tắt") với tổng, trung bình, trung vị, v.v. chỉ được sử dụng làm ví dụ mà tôi đã tạo nhanh chóng - hàm thực mà tôi đang sử dụng để phân tích thực tế phức tạp hơn nhiều. Bất kỳ ý tưởng nào về cách tôi kết hợp một hàm phức tạp hơn vào đoạn mã trên để cung cấp các bảng tóm tắt riêng lẻ giống nhau? -
KT_1 Ngày

@Katie Tôi đoán bạn có thể thay thế summarybằng bất kỳ hàm nào của bạn, miễn là nó lấy data.frame làm đối số (và / hoặc các tham số tùy chọn không đổi trên các DF khác nhau). Ví dụ: lapply(ldf, function(x) apply(x, 2, function(x) c(mean(x), sd(x))))sẽ trả về giá trị trung bình và SD được tính theo màu.
chl

16

thường thì tôi không sử dụng vòng lặp for trong R, nhưng đây là giải pháp của tôi sử dụng vòng lặp for và hai gói: plyrdostats

plyr đang có trên cran và bạn có thể tải xuống dostats trên https://github.com/halpo/dostats (có thể đang sử dụng install_github từ Hadley devtools gói )

Giả sử rằng tôi có hai data.frame đầu tiên của bạn (Df.1 và Df.2) trong các tệp csv, bạn có thể làm như thế này.

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

}

Đây là đầu ra

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) Có vẻ như chúng tôi đã trả lời khá đồng thời và plyrgiải pháp của bạn khá hay!
chl

1
Cảm ơn @dickoa vì câu trả lời của bạn. Chức năng mà tôi đã tạo ("Tóm tắt") được mô tả kém. Tôi chỉ đang sử dụng nó cho mục đích minh họa - chức năng thực của tôi phức tạp hơn nhiều vì vậy tôi đã tự hỏi làm thế nào mã trên (và có thể là hàm của tôi) có thể được thay đổi để nó được áp dụng cho tất cả các khung dữ liệu khác nhau (và không chỉ sử dụng các hàm có sẵn trong R).
KT_1 Ngày

2

Dưới đây là một tidyversetùy chọn có thể không phải là trang nhã nhất, nhưng cung cấp một số tính linh hoạt về những gì được bao gồm trong bản tóm tắt:

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

Giải pháp tuyệt vời vì nó rất linh hoạt. Đối với định dạng dữ liệu của tôi read_csv()không hoạt động đúng cách vì vậy tôi đã thay thế nó bằng data.table::fread().
Thorsten
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.