R Shiny更改daterange显示周期后coefficient值异常修复求助
问题修复方案
问题核心原因
return_coef函数计算系数时需要依赖全量原始数据的所有行、所有DR系列字段做统计计算。你当前代码中在data_subset响应式逻辑里,先按选择的日期范围过滤了数据集,再把过滤后的子集传入return_coef做计算,统计基准随着选择的日期范围变化,才会导致同一日期在不同选择范围下系数值不一致。
修复方法
仅修改server中data_subset部分的逻辑:日期范围过滤仅用来筛选最终要展示的行,计算系数时仍然传入完整的原始数据集即可。同时补充修正原代码中正则表达式未转义、分组残留警告的语法问题。
修复后完整可运行代码
library(shiny) library(shinythemes) library(dplyr) library(writexl) library(tidyverse) library(lubridate) function.test<-function(){ df1 <- structure( list(date1= c("2021-06-28","2021-06-28","2021-06-28"), date2 = c("2021-07-01","2021-07-02","2021-07-04"), Category = c("ABC","ABC","ABC"), Week= c("Wednesday","Wednesday","Wednesday"), DR1 = c(4,1,0), DR01 = c(4,1,0), DR02= c(4,2,0),DR03= c(9,5,0), DR04 = c(5,4,0),DR05 = c(5,4,0),DR06 = c(5,4,0),DR07 = c(5,4,0),DR08 = c(5,4,0)), class = "data.frame", row.names = c(NA, -3L)) return(df1) } return_coef <- function(df1, dmda, CategoryChosse) { x<-df1 %>% select(starts_with("DR0")) x<-cbind(df1, setNames(df1$DR1 - x, paste0(names(x), "_PV"))) PV<-select(x, date2,Week, Category, DR1, ends_with("PV")) med<-PV %>% group_by(Category,Week) %>% summarize(across(ends_with("PV"), median), .groups = "drop") SPV<-df1%>% inner_join(med, by = c('Category', 'Week')) %>% mutate(across(matches("^DR0\\d+$"), ~.x + get(paste0(cur_column(), '_PV')), .names = '{col}_{col}_PV')) %>% select(date1:Category, DR01_DR01_PV:last_col()) SPV<-data.frame(SPV) mat1 <- df1 %>% filter(date2 == dmda, Category == CategoryChosse) %>% select(starts_with("DR0")) %>% pivot_longer(cols = everything()) %>% arrange(desc(row_number())) %>% mutate(cs = cumsum(value)) %>% filter(cs == 0) %>% pull(name) (dropnames <- paste0(mat1,"_",mat1, "_PV")) SPV <- SPV %>% filter(date2 == dmda, Category == CategoryChosse) %>% select(-any_of(dropnames)) if(length(grep("DR0", names(SPV))) == 0) { SPV[head(mat1,10)] <- NA_real_ } datas <-SPV %>% filter(date2 == ymd(dmda)) %>% group_by(Category) %>% summarize(across(starts_with("DR0"), sum), .groups = "drop") %>% pivot_longer(cols= -Category, names_pattern = "DR0(.+)", values_to = "val") %>% mutate(name = readr::parse_number(name)) colnames(datas)[-1]<-c("Days","Numbers") datas <- datas %>% group_by(Category) %>% slice((as.Date(dmda) - min(as.Date(df1$date1) [ df1$Category == first(Category)])):max(Days)+1) %>% ungroup m<-df1 %>% group_by(Category,Week) %>% summarize(across(starts_with("DR1"), mean), .groups = "drop") m<-subset(m, Week == df1$Week[match(ymd(dmda), ymd(df1$date2))] & Category == CategoryChosse)$DR1 if (nrow(datas)<=2){ return (as.numeric(m)) } else if(any(table(datas$Numbers) >= 3) & length(unique(datas$Numbers)) == 1){ yz <- unique(datas$Numbers) return(as.numeric(yz)) } else{ mod <- nls(Numbers ~ b1*Days^2+b2,start = list(b1 = 0,b2 = 0),data = datas, algorithm = "port") return(as.numeric(coef(mod)[2])) } } ui <- fluidPage( shiny::navbarPage(theme = shinytheme("flatly"), collapsible = TRUE, br(), tabPanel("", sidebarLayout( sidebarPanel( uiOutput('daterange'), br() ), mainPanel( dataTableOutput('table'), br(), br(), downloadButton("dl", "Download") ), )) )) server <- function(input, output,session) { data <- reactive(function.test()) data_subset <- reactive({ req(input$daterange1) days <- seq(input$daterange1[1], input$daterange1[2], by = 'day') # 仅筛选要展示的行,不修改原始数据集 df_show <- subset(data(), as.Date(date2) %in% days) df2 <- df_show %>% select(date2,Category) # 计算系数时传入完整原始数据集data(),而非过滤后的子集 Test <- cbind(df2, coef = apply(df2, 1, function(x) {return_coef(data(),x[1],x[2])})) Test }) output$daterange <- renderUI({ dateRangeInput("daterange1", "Period you want to see:", start = min(data()$date2), end = max(data()$date2)) }) output$table <- renderDataTable({ data_subset() }) output$dl <- downloadHandler( filename = function() { "data.xlsx"}, content = function(file) { writexl::write_xlsx(data_subset(), path = file) } ) } shinyApp(ui = ui, server = server)
内容的提问来源于stack exchange,提问作者Antonio
相关产品推荐
相关产品推荐

