Прочитать все файлы в папке и применить функцию к каждому фрейму данных

Я провожу относительно простой анализ, который я ввел в функцию, для всех файлов в определенной папке. Мне было интересно, есть ли у кого-нибудь советы, которые помогут мне автоматизировать процесс для ряда разных папок.

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

Большое спасибо,

Кэти


person KT_1    schedule 05.03.2012    source источник


Ответы (3)


Напротив, я думаю, что работа с 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]])
person chl    schedule 05.03.2012
comment
+1 Я бы plyr::llply (или ldply) вместо lapply, чтобы сохранить имена повсюду, и определить свою собственную итоговую функцию, например plyr::each(min, max, mean, sd, median) - person baptiste; 05.03.2012
comment
+1 @chl: спасибо за трюк с полными именами в функции list.files .... я забыл об этом в своем ответе !!! - person dickoa; 05.03.2012
comment
@baptiste (+1) Спасибо за предложение plyr. - person chl; 05.03.2012
comment
Спасибо @chl. Как мне использовать приведенный выше код с функцией, которую я написал? Пример функции, которую я использовал выше (Сводка) с суммой, средним, медианой и т. Д., Был просто использован в качестве примера, который я быстро создал - реальная функция, которую я использую для своего фактического анализа, намного сложнее. Есть идеи, как включить более сложную функцию в приведенный выше код, чтобы получить те же отдельные сводные таблицы? - - person KT_1; 05.03.2012
comment
@Katie Я думаю, вы можете заменить summary любой своей функцией, при условии, что она принимает data.frame в качестве аргумента (и / или необязательные параметры, которые постоянны в разных DF). Например, lapply(ldf, function(x) apply(x, 2, function(x) c(mean(x), sd(x)))) вернет среднее значение и стандартное отклонение, вычисленное по столбцам. - person chl; 05.03.2012
comment
Это работает хорошо, но я хотел бы увидеть, как объект res можно преобразовать в один dataframe, содержащий все записи из файлов. Может кто-нибудь предложить решение? @chl есть идеи? - person Ben; 07.09.2018

обычно я не использую цикл for в R, но вот мое решение, использующее циклы for и два пакета: plyr и dostats

plyr находится на кране, и вы можете загрузить dostats на https://github.com/halpo/dostats (может использоваться install_github из пакета Hadley devtools)

Предполагая, что у меня есть ваши первые два data.frame (Df.1 и Df.2) в файлах csv, вы можете сделать что-то вроде этого.

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
person dickoa    schedule 05.03.2012
comment
(+1) Похоже, мы ответили одновременно, и ваше plyr решение очень хорошее! - person chl; 05.03.2012
comment
Спасибо @dickoa за ответы. Функция, которую я придумал (Резюме), была описана плохо. Я просто использовал его в иллюстративных целях - моя настоящая функция намного сложнее, поэтому мне было интересно, как можно изменить приведенный выше код (и, возможно, мою функцию), чтобы он применялся ко всем различным фреймам данных (а не только используйте встроенные функции в R). - person KT_1; 05.03.2012

Вот вариант 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
person sbha    schedule 26.03.2019
comment
Отличное решение, так как оно очень гибкое. Для моего формата данных read_csv() не работал должным образом, поэтому я заменил его на data.table::fread(). - person Thorsten; 23.10.2020