如何在Shiny的reactive函数内使用group_by分组数据并计算组占比
问题解决:Shiny reactive中dplyr分组计算占比报错处理
核心问题原因
你遇到的报错本质是dplyr非标准评估的问题:在reactive函数中直接传入Shiny的input变量作为分组列时,dplyr默认会把input变量识别为普通字符串而非数据框的列名,才会出现无法对函数/字符串执行分组的错误。
你现有调整后可以运行的代码是通过data[[input$catgroup]]提取列值实现分组,虽然可以生效,但需要后续手动重命名列,有更简洁的规范写法。
优化后的实现方案
使用dplyr的{{ }}(双大括号运算符,也叫embrace运算符)直接解析动态传入的列名,无需后续手动修改列名,代码可读性和稳定性更高:
仅需要修改你的reactive部分代码即可:
datagr <- reactive({ data %>% # 用{{}}包裹动态列名,dplyr会自动解析为对应列 group_by({{input$catgroup}}, sport,starter) %>% summarize(n = n(), .groups="drop") %>% group_by(sport)%>% mutate( groupcount = sum(n), pog = paste0(round(100*n/groupcount,2),'%') ) %>% # 直接把动态列重命名为后续绘图需要的catgroup rename(catgroup = {{input$catgroup}}) })
对应的绘图部分也可以简化,不需要再手动改列名:
output$myplot <- renderPlotly({ plot_ly(datagr(), x = ~sport, y = ~n, type = "bar", color=~catgroup, colors="Dark2") %>% layout(barmode = 'group') })
你提供的原有可运行代码参考
静态分组占比计算代码
library(flexdashboard) library(dplyr) library(shiny) library(plotly) gender<-c("Male","Female","Female","Female","Male","Male","Male","Male","Female","Female") age<-c(18,19,18,20,21,19,21,20,21,18) sport<-c("Basketball","Basketball","Baseball/Softball","Basketball","Soccer","Baseball/Softball","Basketball","Soccer","Soccer","Soccer") starter<-c("Yes","No","Yes","Yes","Yes","No","Yes","Yes","No","No") data<-data.frame(gender,sport,starter) datagr <- data %>% group_by(gender,age,sport,starter) %>% dplyr::summarise(n=n(), .groups="drop") %>% group_by(sport)%>% mutate(groupcount=sum(n)) %>% mutate(pog=paste0(round(100*n/groupcount,2),'%')) datagr
静态代码输出结果
gender sport starter n groupcount pog <chr> <chr> <chr> <int> <int> <chr> 1 Female Baseball/Softball Yes 1 2 50% 2 Female Basketball No 1 4 25% 3 Female Basketball Yes 1 4 25% 4 Female Soccer No 2 4 50% 5 Male Baseball/Softball No 1 2 50% 6 Male Basketball Yes 2 4 50% 7 Male Soccer Yes 2 4 50%
原有可运行的Shiny完整代码
library(flexdashboard) library(dplyr) library(shiny) library(plotly) gender<-c("Male","Female","Female","Female","Male","Male","Male","Male","Female","Female") age<-c("18","19","18","20","21","19","21","20","21","18") sport<-c("Basketball","Basketball","Baseball/Softball","Basketball","Soccer","Baseball/Softball","Basketball","Soccer","Soccer","Soccer") starter<-c("Yes","No","Yes","Yes","Yes","No","Yes","Yes","No","No") data<-data.frame(gender,age, sport,starter) cat.Variables <- c('gender', 'age') ui <- fluidPage( sidebarPanel( selectInput('catgroup', choices = cat.Variables, label = 'Select filter options:'), conditionalPanel(condition = "input.catgroup != '-'", uiOutput("select_catgroup") ) ), mainPanel(plotlyOutput("myplot")) ) server <- function(input, output) { datagr <- reactive({ data %>% group_by(data[[input$catgroup]], sport,starter) %>% summarize(n = n(), .groups="drop") %>% group_by(sport)%>% mutate(groupcount=sum(n)) %>% mutate(pog=paste0(round(100*n/groupcount,2),'%')) }) output$myplot <- renderPlotly({ datagrt <- datagr() colnames(datagrt) <- c("catgroup","sport","starter","n","groupcount","pog") plot_ly(datagrt, x = ~sport, y = ~n, type = "bar", color=~catgroup, colors="Dark2") %>% layout(barmode = 'group') }) } shinyApp(ui, server)
内容的提问来源于stack exchange,提问作者excelater
相关产品推荐
相关产品推荐

