首页 > 解决方案 > 有没有更优雅的方式在 R Shiny 中动态创建变量?

问题描述

我正在开发一个 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. 两者,renderPlot并在它们的第一行中renderPrint创建data变量(并且data也在 中创建eventReacitve)。是否可以在用户点击提交按钮时创建一次“数据”(此处未显示其实现)?

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

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

标签: rggplot2shinylinear-regression

解决方案


我意识到这可能不是最详尽或令人费解的答案(而且我没有足够的声誉来简单地评论),但作为一般方法,我建议您将所有步骤总结为不同的功能。例如,如果我没看错,您的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 环境中更轻松地测试和调试它们,同时您可以专注于服务器函数中的应用程序。


推荐阅读