在Shiny应用中使用tidyverse summarize处理选中列分组统计的问题
解决Shiny中tidyverse汇总字符串列名的问题
嘿,我完全懂你碰到的麻烦——Shiny传递的列名是字符串格式,但mean()这类基础函数和tidyverse的summarize()默认认的是裸变量名(不带引号的那种),直接把字符串塞进去自然会报错说“不是数值型”。下面给你几个靠谱的解决办法,还能顺便把你要的min、max、mean、sd和计数都整合到结果里:
方法1:用.data代词(最直观)
.data是tidyverse里专门用来通过字符串引用列的工具,它会自动把字符串转换成对应的数据集列。修改后的server代码如下:
server <- function(input, output) { table <- reactive({ mtcars %>% group_by(cyl) %>% summarize( 最小值 = min(.data[[input$summarycol]], na.rm = TRUE), 最大值 = max(.data[[input$summarycol]], na.rm = TRUE), 平均值 = mean(.data[[input$summarycol]], na.rm = TRUE), 标准差 = sd(.data[[input$summarycol]], na.rm = TRUE), 计数 = n() ) }) output$table <- DT::renderDataTable(table()) }
这里加了na.rm = TRUE是为了避免如果数据有缺失值时出错,n()用来统计每组的行数,完全符合你的需求。
方法2:用sym()+!!(准引用方式)
你之前试过加!!但没用,是因为!!需要搭配**符号(symbol)**而不是字符串,所以得先把字符串转成符号:
server <- function(input, output) { table <- reactive({ target_col <- sym(input$summarycol) # 把字符串转成符号 mtcars %>% group_by(cyl) %>% summarize( 最小值 = min(!!target_col, na.rm = TRUE), 最大值 = max(!!target_col, na.rm = TRUE), 平均值 = mean(!!target_col, na.rm = TRUE), 标准差 = sd(!!target_col, na.rm = TRUE), 计数 = n() ) }) output$table <- DT::renderDataTable(table()) }
这种是tidyverse早期的准引用写法,现在依然能用,但.data更简洁直观。
方法3:用across()(现代tidyverse风格)
如果以后想扩展统计量,across()会更灵活,比如可以把要计算的统计量放到一个列表里:
server <- function(input, output) { table <- reactive({ mtcars %>% group_by(cyl) %>% summarize( across(all_of(input$summarycol), list(最小值 = min, 最大值 = max, 平均值 = mean, 标准差 = sd), na.rm = TRUE), 计数 = n() ) %>% # 把列名简化一下,去掉自动加的后缀 rename_with(~gsub(paste0(input$summarycol, "_"), "", .x)) }) output$table <- DT::renderDataTable(table()) }
all_of()用来把字符串列名传递给across(),然后我们可以一次性定义多个统计函数,最后用rename_with()把列名里的原列名前缀去掉,让表格更清爽。
把上面任意一种方法替换到你的原代码里,就能正常生成包含所有需要统计量的表格,不会再出现NA警告啦。
内容的提问来源于stack exchange,提问作者user29609
相关产品推荐
相关产品推荐

