【问题标题】:Uploading multiple files in Shiny, process the files using lapply, rbind the results and return a download在 Shiny 中上传多个文件,使用 lapply 处理文件,rbind 结果并返回下载
【发布时间】:2018-04-03 00:48:49
【问题描述】:

在我之前的post 中,我能够使用for 循环在Shiny 中上传多个文件、处理文件、rbind 并返回一个csv 文件下载。感谢@SBista的贡献。但是,因为我必须一次上传很多文件(总大小约为 50 - 100mb),我发现运行闪亮的应用程序非常慢,这可能是由于for 循环。我知道lapply()reading multiple csv files 循环中比for 循环更快,但是在我的代码中应用lapply() 在运行应用程序后会出现错误(错误:无效的'description' 参数)。任何帮助将不胜感激。这是我的dummy file,这是我的代码:

 library(shiny)

 ui <- fluidPage(
   fluidPage(
     titlePanel("MY CSV FILES MERGER"),
     sidebarLayout(
       sidebarPanel(
         fileInput("file1",
              "Choose CSV files from a directory",
              multiple = TRUE,
              accept=c('text/csv', 
                       'text/comma-separated-values,text/plain', 
                       '.csv')),
         downloadButton('downloadData', 'Download')
       ),
       mainPanel(
         tableOutput('contents')
       )
     )
   )
 )

 library(shiny)
 library(dplyr)
 options(shiny.maxRequestSize = 100*1024^2)
 server <-  function(input, output) {
   getData <- reactive({
     inFile <- input$file1
     if (is.null(inFile)){
       return(NULL)
     }else {   
      files3 = lapply(inFile, function(y){
        JSON_csv = read.csv(y, header = TRUE)
        lastrow = nrow(JSON_csv)
        shift = function(x, n){
          c(x[-(seq(n))], rep(NA, n))
        }
        JSON_csv$companyID1 = shift(JSON_csv$companyID1, 1)
        JSON_csv = JSON_csv[-lastrow, ]
        JSON_csv 
      }

                 )
       do.call(rbind, files3)
     }
   })
   output$contents <- renderTable( 
     getData() 
   )
   output$downloadData <- downloadHandler(
     filename = function() { 
       paste("data-", Sys.time(), ".csv", sep="")
     },
     content = function(file) { 
       write.csv(getData(), file, row.names=FALSE)   
     })
 }

 shinyApp(ui = ui, server = server)

使用for 循环,此代码可以工作,但在处理多个 50-100mb 的 csv 文件时速度非常慢:

 library(shiny)
 library(dplyr)
 server <-  function(input, output) {
 getData <- reactive({
  inFile <- input$file1
  if (is.null(inFile)){
    return(NULL)
  }else {
    # browser()
    numfiles = nrow(inFile) 
    kata_csv1 = list()


    for (i in 1:numfiles)
    {

      JSON_csv = read.csv(input$file1[[i, 'datapath']], header = TRUE)
      lastrow = nrow(JSON_csv)
      shift = function(x, n){
        c(x[-(seq(n))], rep(NA, n))
      }
      JSON_csv$companyID1 = shift(JSON_csv$companyID1, 1)
      kata_csv1[[i]] = JSON_csv[-lastrow, ]

    }
    # browser()
    do.call(rbind, kata_csv1)
     }
   })
  output$contents <- renderTable( 
  getData() 
  )
  output$downloadData <- downloadHandler(
  filename = function() { 
    paste("data-", Sys.Date(), ".csv", sep="")
  },
  content = function(file) { 
    write.csv(getData(), file, row.names=FALSE)   
  })
  }

 shinyApp(ui = ui, server = server)

【问题讨论】:

    标签: r csv shiny


    【解决方案1】:

    问题是当您将inFile 传递给lapply 时,您实际上只传递了包含文件名的第一列。相反,您需要通过inFile$datapath。 lapply 应该是这样的:

       files3 = lapply(inFile$datapath, function(y){
    
         JSON_csv = read.csv(y, header = TRUE)
         lastrow = nrow(JSON_csv)
         shift = function(x, n){
           c(x[-(seq(n))], rep(NA, n))
         }
         JSON_csv$companyID1 = shift(JSON_csv$companyID1, 1)
         JSON_csv = JSON_csv[-lastrow, ]
         JSON_csv 
       }
    

    希望对你有帮助!

    【讨论】:

    • 嗨@Bista,非常感谢您的贡献。但是,当我上传大约 2 个文件时,应用程序运行良好,但是当我上传大约 10 个文件(约 50mb)时,我收到此错误:Warning in scan(file = file, what = what, sep = sep, quote = quote, dec = dec, : EOF within quoted string
    • 也许您的问题与this有关?
    • 嗨@Bista,我找到了error: Warning in scan(file = file, what = what, sep = sep, quote = quote, dec = dec, : EOF within quoted string. 的解决方案。这些参数:quote = "", fill = FALSE 必须包含在 csv() 中。
    【解决方案2】:

    这是一个不使用 for 循环的文件的可能解决方案:

     library(readxl)
        file.list <- list.files(pattern='*.xlsx')
        df.list <- lapply(file.list, read_excel)
    

    闪亮。我在一个单独的脚本中运行我的所有文件,并在闪亮的应用程序中使用“源”引用该脚本

    source("SCRIPTGEO.R", local = TRUE) 
    

    这是一个关于拉取多个文件的链接。 Reading multiple files into R - Best practice

    这是我在脚本中对我的应用所做的。我不是专家,所以可能有其他方法......

        fils1 <- list.files(pattern = ".csv")
    
    
    allquotes <- function(fils1){
      dfs <- lapply(fils1, function(x){
      df <- read.csv(x, header = T, stringsAsFactors = FALSE)
      df <- df[-c(1,nrow(df)),]
      df <- df[,c(1,2,3,5,6,7,8)]
      colnames(df) <-  c("ID", "ENTRY_DATE", "QUOTEORORDER","BILL.TO", "NAME", "BRANCH", "CONVERTED")
      return(df)
      })
      testbind <- do.call("rbind", dfs)
      return(testbind)
    }
    

    【讨论】:

    • 嗨@astronomerforfun。谢谢。我想使用闪亮来上传文件,并使用这部分代码对每个文件执行一些操作` lastrow = nrow(csvfile) shift = function(x, n){ c(x[-(seq(n)) ], rep(NA, n)) } csvfile$companyID1 = shift(csvfilev$companyID1, 1) kata_csv1[[i]] = csvfile[-lastrow, ]. Thereafter, I will now rebind the file. Any help? I was able to that using for`循环
    • 我不太确定你在做什么。但是我将我的代码副本放在原始帖子中。基本上使用 lapply 然后写一个函数来做必要的调整。我自己确实有一段时间遇到过这个问题。
    • 嗨@astronomerforfun。感谢您的贡献。我解决了这个问题。在单独的 R 脚本中读取文件并在闪亮的应用程序中使用“源”引用脚本要快得多。我测试了这两个选项,发现在单独的 R 脚本中读取和执行 10 个大约 90mb 的文件并在闪亮的应用程序中使用“源”引用脚本大约需要 3 分钟,但在我的机器上运行整个代码我的应用程序的 server.R 花了几个小时。
    • 不错!很高兴我能帮助你。正是我对我所做的。我创建了一些闪亮的应用程序。
    猜你喜欢
    • 2018-04-01
    • 2013-12-13
    • 1970-01-01
    • 2017-10-10
    • 1970-01-01
    • 1970-01-01
    • 2011-07-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多