R блестящий foreach вместо двойного для цикла

#r #shiny #foreach

Вопрос:

У меня есть довольно большая симуляция, которую я в настоящее время запускаю в Shiny, используя цикл double for, и это занимает очень много времени. Я читал о возможности использования foreach , но у меня ничего не получается, что бы я ни пробовал, я так и попадаю в ошибки. Может быть, кто-нибудь заметит ошибку и поможет мне ее исправить?

приложение.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)

 

Моей целью было изменить data <-... часть с foreach пакетом, и, поскольку мой компьютер работает на 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)
        }
 

Ответ №1:

Вот способ избежать двойного цикла для использования 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)
 

Здесь вы можете найти эталон с учетом dplyr и data.table (среди прочего).