还有一种更新颖的方法可以在R Shiny中动态创建变量吗?

问题描述 投票:0回答:2

我正在开发R Shiny应用程序,该应用程序允许用户交互地研究线性回归模型的简单原理。我的代码运行得很好。但是,它不是很优雅。在下面找到用于说明的服务器功能(为方便起见,我省略了ui和个人定义的功能,但是如果您要查看它们,请告诉我):

#### Make Server ####
server = function(input, output) {

#if the users presses submit:
#take the input, format it, and forward it to 'simulation' 
#which creates a dataframe(column1 = simulated response, column2 = group)
  simulate <- eventReactive(input$submit, {
    group1 = as.numeric(c(input$n1, input$mean1, input$sd1))
    group2 = as.numeric(c(input$n2, input$mean2, input$sd2))
    group3 = as.numeric(c(input$n3, input$mean3, input$sd3))
    all_groups = list(group1, group2, group3)
    data = simulation(all_groups)
    })

#model a linear regression based on the simulated data, print the output
  output$model <- renderPrint({
    data = simulate()
    model = lm(response ~ group,
               contrasts = list(group = "contr.sum"),
               data = data)
    summary(model)
  })

#plot density plots for every group in one graph
#add the intercepts/coefficients returned by the linear regression to that graph
  output$hist <- renderPlot({
    data = simulate()
    model = lm(response ~ group,
               contrasts = list(group = "contr.sum"),
               data = data)
    intercept = model[["coefficients"]][["(Intercept)"]]
    intercept_g1 = model[["coefficients"]][["group1"]]
    intercept_g2 = model[["coefficients"]][["group2"]]
    ggplot(data, aes(x=response, fill=group)) + 
      geom_density(data = subset(data, group="group1"), alpha=.5) + 
      geom_density(data = subset(data, group="group2"), alpha=.5) +
      geom_density(data = subset(data, group="group3"), alpha=.5) +
      geom_vline(xintercept=intercept) +
      geom_vline(xintercept=intercept_g1) +
      geom_vline(xintercept=intercept_g2)
  })

#if the user presses 'reset', reset all input panels to their default value
  observeEvent(input$reset, {
    shinyjs::reset("side-panel")
  })
}

困扰我的两个主要问题是:

  1. B renderPlotrenderPrint都在其第一行中创建data变量(并且data也在eventReacitve中创建)。当用户点击“提交”按钮时,是否可以一次创建“数据”(此处未显示其实现)?

  2. Both,renderPlotrenderPrint都计算线性回归模型。虽然第一个仅需要输出,但是第二个需要一些值,这些值存储在lme变量中(此处为截距)。这里也可以只计算一次模型吗?

[如果您还建议改善代码,但又不解决其他问题,请告诉我。这只是较大项目的一小部分;将为用户添加几个选项,并且高效且易于维护的代码将非常有用!

r ggplot2 shiny linear-regression
2个回答
0
投票

我意识到这可能不是最详尽或最复杂的答案(并且我没有足够的声誉来简单评论),但是作为一种通用方法,我建议您将所有步骤总结为不同的功能。例如,如果我正确地看到了这一点,则您的renderPlot()调用仅取决于simulate(),而其余计算基于simulate()提供的数据。因此,您可以将其总结为

plot_data <- function(data_input) {
    data = data_input
    model = lm(response ~ group,
               contrasts = list(group = "contr.sum"),
               data = data)
    intercept = model[["coefficients"]][["(Intercept)"]]
    intercept_g1 = model[["coefficients"]][["group1"]]
    intercept_g2 = model[["coefficients"]][["group2"]]
    ggplot(data, aes(x=response, fill=group)) + 
      geom_density(data = subset(data, group="group1"), alpha=.5) + 
      geom_density(data = subset(data, group="group2"), alpha=.5) +
      geom_density(data = subset(data, group="group3"), alpha=.5) +
      geom_vline(xintercept=intercept) +
      geom_vline(xintercept=intercept_g1) +
      geom_vline(xintercept=intercept_g2)
}

这将减少您的呼叫到

output$hist <- renderPlot({plot_data(simulate())})

此外,在闪亮的应用程序外部编写这些功能还可以使您在普通的R环境中更轻松地测试和调试它们,而您可以专注于服务器功能中的应用程序。


0
投票

[我认为您应该在另一个reactive中计算模型,这样您可以在eventReactive中设置数据并创建一个get_model反应式,您可以在其中读取datarender*函数您使用此模型。

伪代码可能是这些东西:

server <- function(input, output, session) {
  ## create a get_model reactive
  ## thanks to the reactive nature it will cache its values unless data changes
  get_model <- reactive({
     my_data <- req(simulate()) ## use require to make sure it is well defined
     lm(response ~ group, 
        contrasts = list(group = "contr.sum"),
        data = my_data)
  })

  output$model <- renderPrint({
    ## you could use validate(need(.)) here to make sure the model is well defined
    ## validate(need(get_model(), "Model not yet defined! Please simulate some data first!")
    summary(get_model()))
  })
}

这样,您仅在数据更改时计算模型,在renderPrintrenderPlot中仅计算一次,而不计算两次。无论如何,仅在按下按钮时才重新生成数据。这样,您可以充分利用shiny's内置电抗系统。


我刚刚看到您的绘图函数中也需要data,所以我只想做这样的事情:

simulate <- eventReactive(input$submit, {
   ## create data first
   group1 <- as.numeric(c(input$n1, input$mean1, input$sd1))
   group2 <- as.numeric(c(input$n2, input$mean2, input$sd2))
   group3 <- as.numeric(c(input$n3, input$mean3, input$sd3))
   all_groups <- list(group1, group2, group3)
   data <- simulation(all_groups)
   ## create model
   model <- lm(response ~ group, 
        contrasts = list(group = "contr.sum"),
        data = data)
   ## return a list with both elements
   list(data = data, model = model)
})

然后您可以像这样在renderPrint中使用它:

output$model <- renderPrint({
   summary(simulate()$data))
})

在这样的渲染图中

output$hist <- renderPlot({
   data  <- simulate()$data
   model <- simulate()$model
   intercept = model[["coefficients"]][["(Intercept)"]]
   intercept_g1 = model[["coefficients"]][["group1"]]
   intercept_g2 = model[["coefficients"]][["group2"]]
   ggplot(data, aes(x=response, fill=group)) + 
      geom_density(data = subset(data, group="group1"), alpha=.5) + 
      geom_density(data = subset(data, group="group2"), alpha=.5) +
      geom_density(data = subset(data, group="group3"), alpha=.5) +
      geom_vline(xintercept=intercept) +
      geom_vline(xintercept=intercept_g1) +
      geom_vline(xintercept=intercept_g2)
})
© www.soinside.com 2019 - 2024. All rights reserved.