【问题标题】:How can I download data depending on reactive values in RShiny?如何根据 R Shiny 中的反应值下载数据?
【发布时间】:2020-01-12 14:10:15
【问题描述】:

我是 RShiny 的新手。我在 R 中创建了一个模型,并希望使用 RShiny 使其用户友好。

它绘制了一些直方图和移动平均图(目前正在工作),但我也希望能够在单击“模拟”按钮并触发反应值时下载我的模拟。

由于我使用了 reactiveValues(),并且我使用了一些单独的信​​息进行绘图,因此我从每次点击“模拟按钮”时获得的反应值创建了“my.download”。但是可下载的 .csv 文件给了我两列(我使用的是带有 5 个向量的 cbind),其中的数字绝对是奇数。如果我模拟 1000 个案例,它会给我 5000 行;如果是 2000 个案例,10000 行等。

这是与我要将数据转换为的 .csv 文件相关的代码部分。

library(data.table)
library(shiny)
library(ggplot2)
### My functions ###

claims.frequency = function(iterations, dist, lambda, size, prob){
  freq = rep(NA,iterations)
  if(dist == "Poisson"){freq_dt = data.table(i=1:iterations)[,list(freq=rpois(n=1,lambda=lambda)),by=i]}
  else if(dist == "Negative Binomial"){freq_dt = data.table(i=1:iterations)[,list(freq=rnbinom(n=1,size=size,prob=prob)),by=i]}
  return(freq_dt$freq)
}

claims.severity <- function(frequency,dist,meanlog,sdlog,shape,scale,rate,percentile){
  sever = rep(NA,length(frequency))
  moving_average = rep(NA,length(frequency))
  moving_percentile = rep(NA,length(frequency))
  df = rep(NA,length(frequency))
  if(dist=="Lognormal"){sever_dt=data.table(i=1:length(frequency))[,list(sever=sum(rlnorm(n=frequency[i],meanlog=meanlog,sdlog=sdlog))),by=i]}
  else if(dist=="Gamma"){sever_dt=data.table(i=1:length(frequency))[,list(sever=sum(rgamma(n=frequency[i],shape=shape,rate=rate))),by=i]}
  else if(dist=="Exponential"){sever_dt=data.table(i=1:length(frequency))[,list(sever=sum(rexp(n=frequency[i],rate=1/rate))),by=i]}
  else if(dist=="Weibull"){sever_dt=data.table(i=1:length(frequency))[,list(sever=sum(rweibull(n=frequency[i],shape=shape,scale=scale))),by=i]}

  moving_average_dt = data.table(i=1:length(frequency))[,list(moving_average=mean(sever_dt$sever[1:i])),by=i]
  moving_percentile_dt = data.table(i=1:length(frequency))[,list(moving_percentile=quantile(sever_dt$sever[1:i],probs=percentile)),by=i]

  df = cbind(frequency,sever_dt$sever,moving_average_dt$moving_average,moving_percentile_dt$moving_percentile)
  colnames(df) = c("# Claims","Aggregate Claims Value","Moving Average","Moving Percentile")
  return(as.data.frame(df))
}

### UI ###

ui <- fluidPage(
  titlePanel('Simulator'),
  sidebarPanel(
    sliderInput(inputId="n", "Iterations", value = 250500, min = 1000, max = 500000, step = 500, round = TRUE, ticks = TRUE),
    radioButtons("freq.dist", "Frequency Distributions:",
                 c("Poisson (\\(\\lambda\\))" = "P",
                   "Negative Binomial (n, p)" = "B")),
    numericInput("paramfreq1","\\(\\lambda\\), if Poisson; or n, if Negative Binomial",0),
    numericInput("paramfreq2","p",0),
    radioButtons("sever.dist", "Severity Distributions:",
                 c("Lognormal (\\(\\mu\\ ,  \\sigma\\))" = "L",
                   "Gamma (\\(\\alpha\\ ,  \\beta\\))" = "G",
                   "Exponential (\\(\\lambda\\))" = "E",
                   "Weibull (\\(\\alpha\\ ,  \\beta\\))" = "W")),
    numericInput("paramsever1","\\(\\mu\\), if Lognormal; \\(\\alpha\\), if Gamma or Weibull; or \\(\\lambda\\), if Exponential",0),
    numericInput("paramsever2","\\(\\sigma\\), if Lognormal; or \\(\\beta\\), if Gamma or Weibull",0),
    actionButton("simulate","Simulate"),
    downloadButton('downloadData', 'Download')
  )
)

### SERVER ###

server <- function(input, output) {

  rv <- reactiveValues(my.freq = 0,
                       my.total.claims = 0,
                       my.moving.average = 0,
                       my.moving.percentile = 0,
                       my.download = 0)

  observeEvent(input$simulate,
               {
                 my.freq <- switch(input$freq.dist,
                                   "P" = claims.frequency(iterations = input$n,
                                                          dist = "Poisson",
                                                          lambda = input$paramfreq1),
                                   "B" = claims.frequency(iterations = input$n,
                                                          dist = "Negative Binomial",
                                                          size = input$paramfreq1,
                                                          prob = input$paramfreq2))

                 my.sever <- switch(input$sever.dist,
                                    "L" = claims.severity(frequency = my.freq,
                                                          dist = "Lognormal",
                                                          meanlog = input$paramsever1,
                                                          sdlog = input$paramsever2,
                                                          percentile = .995),
                                    "G" = claims.severity(frequency = my.freq,
                                                          dist = "Gamma",
                                                          shape = input$paramsever1,
                                                          rate = input$paramsever2,
                                                          percentile = .995),
                                    "E" = claims.severity(frequency = my.freq,
                                                          dist = "Exponential",
                                                          rate = input$paramsever1,
                                                          percentile = .995),
                                    "W" = claims.severity(frequency = my.freq,
                                                          dist = "Weibull",
                                                          shape = input$paramsever1,
                                                          scale = input$paramsever2,
                                                          percentile = .995))

                 rv$my.freq <- as.numeric(my.freq)
                 rv$my.total.claims <- as.numeric(my.sever$`Aggregate Claims Value`)
                 rv$my.moving.average <- as.numeric(my.sever$`Moving Average`)
                 rv$my.moving.percentile <- as.numeric(my.sever$`Moving Percentile`)
                 rv$my.download <- (as.numeric(cbind(1:length(my.freq), my.sever$`# Claims`,my.sever$`Aggregate Claims Value`,my.sever$`Moving Average`,my.sever$`Moving Percentile`))) ### PROBLEM HERE ###
               }
  )

  output$downloadData <- downloadHandler(
    filename = function(){
      paste('simulation-', Sys.time(), '.csv', sep='')
    },
    content = function(file){
      write.table(x = rv$my.download, file, dec = "," , sep = ";")
    })
}

我希望输出具有正确的列(以及列名,但是当我尝试添加它时,它会返回以下错误):

Warning: Error in colnames<-: attempt to set 'colnames' on an object with less than two dimensions

但我的 .csv 文件如下:https://i.imgur.com/zRKLetW.png

虽然预期的输出是:https://i.imgur.com/7PJNBny.png

如何解决?

【问题讨论】:

  • 更新:代码现在可以工作了。我只是在 my.download 的每个向量中单独使用 as.numeric()。然后我在 write.table 中将 row.names 设置为 FALSE。

标签: r shiny reactive


【解决方案1】:

我不确定这是否是整个问题,但我认为部分问题在于您将呼叫 cbind() 包裹在 as.numeric()

例如 as.numeric(cbind(1:3, 4:6)) 返回一个数值向量,其中 cbind(1:3, 4:6) 返回一个矩阵。您还可以使用data.frame(col_name1 = vector1, col_name2 = vector2...) 来确保 rv$mydownload 的导出格式正确。

【讨论】:

    猜你喜欢
    • 2019-04-07
    • 2018-07-29
    • 2020-02-12
    • 1970-01-01
    • 1970-01-01
    • 2015-01-23
    • 2015-08-07
    • 1970-01-01
    • 2021-11-20
    相关资源
    最近更新 更多