Как импортировать несколько листов из нескольких файлов Excel в один список - readxl R - PullRequest
0 голосов
/ 06 июля 2018

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

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

Когда я выполняю цикл, я получаю вывод только из первого члена списка (файлы [1]) вместо вывода из всех итераций цикла, добавленных в объект списка all_data.

Вот мой код:

# name filepath of excel files to import
file_path ="..."

# load names of excel files 
files = list.files(path = file_path, pattern = ".xlsx", )

# create list to store data
all_data = list()

# create function to read multiple sheets per excel file
read_excel_allsheets <- function(filename, tibble = FALSE) {
  sheets <- readxl::excel_sheets(filename)
  x <- lapply(sheets, function(X) readxl::read_excel(filename, sheet = X))
  x <- lapply(x, as.data.frame)
  names(x) <- sheets
  }

# execute function for all excel files in "files"
for (i in length(files)){
  filename = paste0(file_path,"/", files[i])
  read_excel_allsheets(filename)
  all_data = c(all_data, x)
  }

Я подозреваю, что просто делаю фундаментальную ошибку цикла, но искал вокруг и не могу найти, как исправить. любая помощь очень ценится!

Ответы [ 3 ]

0 голосов
/ 06 июля 2018

Для нескольких листов в нескольких файлах Excel требуется вложенный цикл. Рассмотрим вложенные lapply звонки. В частности, вернуть соответствующий объект, так как прямо сейчас он возвращает листов для каждого вызова функции. Затем преобразуйте for в lapply для списка объектов:

# load names of excel files 
files = list.files(path = "...", full.names = TRUE, pattern = ".xlsx")

# create function to read multiple sheets per excel file
read_excel_allsheets <- function(filename, tibble = FALSE) {
  sheets <- readxl::excel_sheets(filename)
  tibble_list <- lapply(sheets, function(sh) readxl::read_excel(filename, sheet = sh)
  df_list <- lapply(x, as.data.frame)
  names(df_list) <- sheets                 

  return(df_list)
}

# execute function for all excel files in "files"
all_data <- lapply(files, read_excel_allsheets)

Четное имя вас all_data список по базовому имени каждого файла:

# name outer list
xl_base_names <- lapply(files, basename)
all_data <- setNames(all_data, xl_base_names)

В качестве альтернативы, сократите свою функцию и используйте sapply(..., ..., simplify = FALSE), который по умолчанию перечисляет имена по предоставленному вектору символов:

read_excel_allsheets <- function(filename, tibble = FALSE) {
  sheets <- readxl::excel_sheets(filename)
  sapply(sheets, function(f) as.data.frame(readxl::read_excel(filename, sheet = f)), 
         simplify = FALSE)
}
0 голосов
/ 18 июля 2018

Вот опция, которая возвращает фрейм данных со столбцами для имен файлов и листов для каждого файла. В этом примере не каждый файл имеет одинаковые листы или столбцы; test2.xlsx имеет только один лист, а test3.xlsx sheet1 не имеет col3.

library(tidyverse)
library(readxl)

dir_path <- "~/test_dir/"         # target directory where the xlsx files are located. 
re_file <- "^test[0-9]\\.xlsx"    # regex pattern to match the file name format, in this case 'test1.xlsx', 'test2.xlsx' etc.

read_sheets <- function(dir_path, file){
  xlsx_file <- paste0(dir_path, file)
  xlsx_file %>%
    excel_sheets() %>%
    set_names() %>%
    map_df(read_excel, path = xlsx_file, .id = 'sheet_name') %>% 
    mutate(file_name = file) %>% 
    select(file_name, sheet_name, everything())
}

df <- list.files(dir_path, re_file) %>% 
  map_df(~ read_sheets(dir_path, .))

# A tibble: 15 x 5
   file_name  sheet_name  col1  col2  col3
   <chr>      <chr>      <dbl> <dbl> <dbl>
 1 test1.xlsx Sheet1         1     2     4
 2 test1.xlsx Sheet1         3     2     3
 3 test1.xlsx Sheet1         2     4     4
 4 test1.xlsx Sheet2         3     3     1
 5 test1.xlsx Sheet2         2     2     2
 6 test1.xlsx Sheet2         4     3     4
 7 test2.xlsx Sheet1         1     3     5
 8 test2.xlsx Sheet1         4     4     3
 9 test2.xlsx Sheet1         1     2     2
10 test3.xlsx Sheet1         3     9    NA
11 test3.xlsx Sheet1         4     7    NA
12 test3.xlsx Sheet1         5     3    NA
13 test3.xlsx Sheet2         1     3     4
14 test3.xlsx Sheet2         2     5     9
15 test3.xlsx Sheet2         4     3     1
0 голосов
/ 06 июля 2018

посмотрите, работает ли что-то подобное для вас:

library(readxl)
library(fs)
library(purrr)

file_names <- dir_ls("folder_name",
                     glob = "*.xlsx", ignore.case = TRUE)

x <- map_df(file_names, function(x){  
                 sheet_names <- excel_sheets(x)
                 raw_data <- map_df(sheet_names, ~read_excel(x, sheet = .x)) 
                 return(raw_data)})
...