Объединить несколько файлов Excel, начиная со строки в R - PullRequest
0 голосов
/ 24 октября 2018

У меня есть несколько файлов Excel, которые мне нужно объединить в один, но только определенные строки.Файлы Excel выглядят так ...

Заголовки столбцов одинаковы для всех файлов.Мне также нужно добавить новый столбец A во вновь созданный файл, поэтому я создал отдельный файл Excel, содержащий только заголовки и новый столбец A. Мой сценарий сначала читает этот файл (ниже) и записывает его в книгу..

Далее мне нужно прочитать каждый файл, начиная со строки 9, и объединить все данные один за другим.Таким образом, конечный результат должен выглядеть следующим образом (за исключением столбца сайта участника, я еще не пробовал логику для этого, но думаю, что это будет подстрока значения идентификатора образца) ...

Однако,мой текущий результат ...

В настоящее время я использую только 3 файла, каждый из которых содержит несколько десятков строк, но конечная цель - объединить около 15-30 файлов, каждый из которых содержит от 25 до 200 строк., дай или возьми.Итак ...

1) Я знаю, что мой код неверен, но не уверен, как получить ожидаемые результаты.С одной стороны, мой цикл перезаписывает данные, потому что он постоянно начинается со строки / столбца 2 при записи.Тем не менее, я не могу думать, как переписать это.

2) Даты возвращаются в общем формате («43008» вместо «30.09.2017»)

3) Некоторые данные столбцов помещаются в разные столбцы (например, Нуклеиновая кислота)Концентрация имеет значения из Даты содержания ткани).

Буду признателен за любой совет или помощь!

Мой код ...

library(openxlsx)   # Excel and csv files
library(svDialogs)   # Dialog boxes

setwd("C:/Users/Work/Combined Manifest")

# Create and load Excel file
wb <- createWorkbook()

# Add worksheet
addWorksheet(wb, "Template")

# Read in & write header file
df.headers <- read.xlsx("headers.xlsx", sheet = "Template")

writeData(wb, "Template", df.headers, colNames = TRUE)

# Function to get user path
getPath <- function() { 
  # Ask for path
  path <- dlgInput("Enter path to files: ", Sys.info()["user"])$res
  if (dir.exists(path)) {
    # If path exists, set the path as the working directory
    return(path)
  } else {
    # If not, issue an error and recall the getPath function
    dlg_message("Error: The path you entered is not a valid directory. Please try again.")$res
    getPath()
  }
}

# Call getPath function
folder <- getPath()

setwd(folder)

# Get list of files in directory
pattern.ext <- "\\.xlsx$"
files <- dir(folder, full=TRUE, pattern=pattern.ext)

# Get basenames and remove extension 
files.nms <- basename(files)
files.nms <- gsub(pattern.ext, "", files.nms)

# Set the names
names(files) <- files.nms

# Iterate to read in files and write to new file
for (nm in files.nms) {

  # Read in files 
  df <- read.xlsx((files[nm]), sheet = "Template", startRow = 9, colNames = FALSE)

  # Write data to sheet
  writeData(wb, "Template", df, startCol = 2, startRow = 2, colNames = FALSE)
}

saveWorkbook(wb, "Combined.xlsx", overwrite = TRUE)

РЕДАКТИРОВАТЬ: Итак, с помощью цикла ниже, я успешно читаю файлы и объединяю их.Спасибо за помощь!

for (nm in files.nms) {

  # Read in files 
  df <- read.xlsx(files[nm], sheet = "Template", startRow = 8, colNames = TRUE, detectDates = TRUE, skipEmptyRows = FALSE,
                  skipEmptyCols = FALSE)

  # Append the data
  allData <- rbind(allData, df)
}

РЕДАКТИРОВАТЬ: ОКОНЧАТЕЛЬНОЕ РЕШЕНИЕ Спасибо всем за помощь !!

library(openxlsx)   # Excel and csv files
library(svDialogs)   # Dialog boxes

# Create and load Excel file
wb <- createWorkbook()

# Add worksheet
addWorksheet(wb, "Template")

# Function to get user path
getPath <- function() { 
  # Ask for path
  path <- dlgInput("Enter path to files: ", Sys.info()["user"])$res
  if (dir.exists(path)) {
    # If path exists, set the path as the working directory
    return(path)
  } else {
    # If not, issue an error and recall the getPath function
    dlg_message("Error: The path you entered is not a valid directory. Please try again.")$res
    getPath()
  }
}

# Call getPath function
folder <- getPath()

# Set working directory
setwd(folder)

# Get list of files in directory
pattern.ext <- "\\.xlsx$"
files <- dir(folder, full=TRUE, pattern=pattern.ext)

# Get basenames and remove extension 
files.nms <- basename(files)

# Set the names
names(files) <- files.nms

# Create empty dataframe
allData <- data.frame()

# Create list (reserve memory)
f.List <- vector("list",length(files.nms))

# Look and load files
for (nm in 1:length(files.nms)) {

  # Read in files
  f.List[[nm]] <- read.xlsx(files[nm], sheet = "Template", startRow = 8, colNames = TRUE, detectDates = TRUE, skipEmptyRows = FALSE,
                  skipEmptyCols = FALSE)
}

# Append the data
allData <- do.call("rbind", f.List)

# Add a new column as 'Member Site'
allData <- data.frame('Member Site' = "", allData)

# Take the substring of the Specimen.ID column for Memeber Site
allData$Member.Site <- sapply(strsplit(allData$Specimen.ID, "-"), "[", 2)

# Write data to sheet
writeData(wb, "Template", startCol = 1, allData)

# Save workbook
saveWorkbook(wb, "Combined.xlsx", overwrite = TRUE)

1 Ответ

0 голосов
/ 25 октября 2018

Прежде всего, вы предоставляете много информации в своем вопросе, что, как правило, хорошо, но мне интересно, могли бы вы облегчить решение ваших проблем, воссоздав проблему, используя все меньше и меньше файлов.Не могли бы вы выяснить, как объединить два файла, каждый из которых сначала содержит небольшое количество данных?

Что касается первого вызова, который вы поднимаете:

1) Да, вы перезаписываете книгу в каждом цикле.Я бы посоветовал вам загрузить данные и добавить их в data.frame, а затем сохранить конечный результат после загрузки всех файлов.Посмотрите на пример ниже.Обратите внимание, что в этом примере используется rbind, который неэффективен, если вы объединяете большое количество файлов.Поэтому, если у вас много файлов, вам может понадобиться использовать другую структуру.

# Create and empty data frame
allData <- data.frame()

# Loop and load files
for(nm in files.nms) {

    # Read in files 
    df <- read.xlsx((files[nm]), sheet = "Template", startRow = 9, colNames = FALSE)

    # Append the data
    allData <- rbind(allData, df)

}

# Write data to sheet
writeData(wb, "Template", df, startCol = 2, startRow = 2, colNames = FALSE)

Надеюсь, это приблизит вас к тому, что вам нужно!

Редактировать: Обновление ответа с учетом сделанных комментариев

Если у вас естьБолее чем в нескольких файлах rbind будет работать медленно, как упомянуто @Parfait, из-за нескольких копий создаваемых данных.Чтобы избежать этого, нужно сначала зарезервировать место в памяти, создав пустой список с достаточным пространством для хранения ваших данных, затем заполнить список и только в конце объединить все данные вместе с помощью do.call ("rbind")....).Ниже я скомпилировал пример кода, который соответствует тому, что вы указали в своем вопросе.

# Create list (reserve memory)
f.List <- vector("list",length(files.nms))

# Loop and load files
for(eNr in 1:length(files.nms)) {

    # Read in files 
    f.List[[eNr]] <- read.xlsx((files.nms[eNr]), sheet = "Template", startRow = 9)

}

# Append the data
allData <- do.call("rbind", f.List)

Ниже для иллюстрации этого приведен небольшой воспроизводимый пример.Он использует только пару фреймов данных, но он иллюстрирует процесс создания списка, заполнения этого списка и объединения данных в качестве последнего шага.

# Sample data
df1 <- data.frame(x=1:3, y=3:1)
df2 <- data.frame(y=4:6, x=3:1)
df.List <- list(df1,df2)

# Create list
d.List <- vector("list",length(df.List))

# Loop and add data
for(eNr in 1:length(df.List)) {
    d.List[[eNr]] <- df.List[[eNr]] 
}

# Bind all at once
dfAll <- do.call("rbind", d.List)
print(dfAll)

Надеюсь, это поможет!Спасибо!

...