R shiny foreach 而不是 double for 循环

R shiny foreach instead of double for loop

我有一个相当大的模拟,我目前 运行 在 Shiny 中使用双 for 循环,这需要很长时间。我阅读了有关使用 foreach 的可能性的信息,但无论我尝试什么,它都行不通,但我还是出错了。也许有人可以发现错误并帮助我更正它?

app.R 运行 秒(尽管(在实际数据上)非常慢,这里有 reprex

的示例数据
require(shiny)
require(tidyverse)
require(foreach) 
require(doMC) 
registerDoMC() 
options(cores = detectCores())

df <- data.frame(a=rnorm(n=26), b=1:26, c=100:125)

calc <- function(let=0.5, var1=0.1, var2=0.5){
  df%>%
    mutate(p1=ifelse(a<let,var1,0))%>%
    mutate(p2=ifelse(a<let, var2,2))%>%
    summarise(mean_b=mean(b*p1),
              mean_c=mean(c*p2))
}

# Define UI for application that draws a histogram
ui <- fluidPage(
  
  # Application title
  titlePanel("Example"),
  
  # Sidebar with a slider input for number of bins 
  sidebarLayout(
    sidebarPanel(
      sliderInput(inputId="selected_let", 
                  label="LET", 
                  value=0.5, 
                  min=0, 
                  max=1, 
                  step=0.1),
      
      submitButton("CALCULATE")
      
      
    ),
    
    
    # Show a plot of the generated distribution
    mainPanel(
      h1(paste0("Table1")),
      tableOutput("table_1"),
      
      h1(paste0("Table2")),
      tableOutput("table_2")
    )
  )
)

# Define server logic required to draw a histogram
server <- function(input, output) {

  
  
  data <- reactive({
    
    data <- data.frame()
    
    for (i in seq(0,1,by=0.1)) {
      for (j in seq(0,1,by=0.1)) {
        
        tmp <- calc(let = input$selected_let, var1 = i, var2 = j)
        tmp_df <- data.frame(var1=i, 
                             var2=j, 
                             mean_b=tmp$mean_b, 
                             mean_c=tmp$mean_c)
        data <- rbind(data, tmp_df)
        
      }
    }
    return(data)
    
  })
  
  
  output$table_1 <-  renderTable({
    data()%>%
      select(var1,var2,mean_b)%>%
      spread(var2, mean_b)
  })
  
  
  output$table_2 <-  renderTable({    
    data()%>%
      select(var1,var2,mean_c)%>%
      spread(var2, mean_c)
  })
  
  
}

# Run the application 
shinyApp(ui = ui, server = server)

我的目标是用 foreach 包更改 data <-... 部分,作为我的 PC 运行s on UNIX 我使用 doMC.

将替换为:

data <- reactive({
  
  foreach(i=rep(seq(0,1,by=0.1),each=11), 
          j=rep(seq(0,1,by=0.1),times=11), 
          .combine="rbind") %dopar% {
            
            val <- calc(let=input$selected_let,
                        var1=i, 
                        var2=j)
            
            data.frame(var1=i, 
                       var2=j, 
                       mean_b=tmp$mean_b, 
                       mean_c=tmp$mean_c)
          }
  
})

但这最终会导致永久性错误:

我试图在服务器部分退出 require(dplyr),但这也无济于事。 对解决方案有什么建议吗?

作为独立的,foreach 部分 运行 可以很好地使用 let=0.5 作为输入,因为它不在 reactive

foreach(i=rep(seq(0,1,by=0.1),each=11), 
        j=rep(seq(0,1,by=0.1),times=11), 
        .combine="rbind") %dopar% {
          
          val <- calc(let=0.5,
                      var1=i, 
                      var2=j)
          
          data.frame(var1=i, 
                     var2=j, 
                     mean_b=tmp$mean_b, 
                     mean_c=tmp$mean_c)
        }

这里有一个避免双重 for 循环的方法 library(data.table):

library(shiny)
library(data.table)

set.seed(0)

DF <- data.frame(a = rnorm(n = 26), b = 1:26, c = 100:125)
setDT(DF)

DT <- setDT(expand.grid(var1 = seq(0, 1, by = 0.1), var2 = seq(0, 1, by = 0.1)))
setorder(DT, var1, var2)

calc <- function(DF, let = 0.5, var1 = 0.1, var2 = 0.5) {
  DF[, c("mean_b", "mean_c") := .(b * fifelse(a < let, var1, 0), c * fifelse(a < let, var2, 2))]
  as.list(colMeans(DF[, .(mean_b, mean_c)]))
}

ui <- fluidPage(titlePanel("Example"),
                sidebarLayout(
                  sidebarPanel(
                    sliderInput(
                      inputId = "selected_let",
                      label = "LET",
                      value = 0.5,
                      min = 0,
                      max = 1,
                      step = 0.1
                    ),
                    submitButton("CALCULATE")
                  ),
                  mainPanel(
                    h1(paste0("Table1")),
                    tableOutput("table_1"),
                    h1(paste0("Table2")),
                    tableOutput("table_2")
                  )
                ))

server <- function(input, output) {
  data <- reactive({
    DT[, c("mean_b", "mean_c") := calc(DF, let = input$selected_let, var1 = var1, var2 = var2), by = seq_len(NROW(DT))]
  })
  
  output$table_1 <- renderTable({
    dcast(data(), var1 ~ var2, value.var = "mean_b")
  })
  
  output$table_2 <- renderTable({
    dcast(data(), var1 ~ var2, value.var = "mean_c")
  })
}

shinyApp(ui = ui, server = server)

Here 你可以找到一个考虑到 dplyr 和 data.table (以及其他)的基准。