为什么从求和切换到计算唯一出现次数时,dplyr 中的 group_by() 不起作用?

Why does group_by() in dplyr not work when switching from sum to counting unique occurrences?

下面的 MWE 代码适用于汇总数据帧值,用户可以在“对数据 table 列求和:”部分中的单选按钮中选择要分组的周期类型底部。此分组在下面 server 部分的 summed_data() 对象中执行。

但是我也在尝试计算 Period_2 == 1 的出现次数。当我注释掉下面当前未注释的 summed_data() 部分,并取消注释当前注释掉的 summed_data() 执行唯一行计数,并尝试 运行ning 代码,它失败了。但是,如果我 运行 R 控制台中的这个独特的行计数函数,如下所示,它工作正常并给出所需的结果(手动更改 group_by(...) 部分中的“Period...”) !

   data <- data.frame(
      ID = c(115,115,111,88,120,16),
      Period_1 = c("2020-01", "2020-02", "2020-03", "2020-01", "2020-02", "2020-03"),
      Period_2 = c(1, 2, 3, 1, 1, 4),
      ColA = c(1000.01, 20, 30, 40, 50, 60),
      ColB = c(15.06, 25, 35, 45, 55, 65)
    )
    
    filter(data, Period_2 == "1") %>%
    group_by(Period_1) %>%
    summarise(count = length(unique(ID)))

 Period_1 count
  <chr>    <int>
1 2020-01      2
2 2020-02      1

所以,对我来说,问题似乎在于下面的 dplyr 代码 group_by(!!sym(input$grouping))。有人有解决这个问题的建议吗?

MWE 代码:

library(dplyr)
library(DT)
library(shiny)
library(shinyWidgets)
library(tidyverse)

ui <-
  fluidPage(
    fluidRow(
      column(width = 8,
          h3("Data table:"),
          tableOutput("data"),
          h3("Sum the data table columns:"),
          radioButtons(
            inputId = "grouping",
            label = NULL,
            choiceNames = c("By period 1", "By period 2"),
            choiceValues = c("Period_1", "Period_2"),
            selected = "Period_1",
            inline = TRUE
          ),
          DT::dataTableOutput("sums")
      )
    )
  )

server <- function(input, output, session) {
  data <- reactive({
    data.frame(
      ID = c(115,115,111,88,120,16),
      Period_1 = c("2020-01", "2020-02", "2020-03", "2020-01", "2020-02", "2020-03"),
      Period_2 = c(1, 2, 3, 1, 1, 4),
      ColA = c(1000.01, 20, 30, 40, 50, 60),
      ColB = c(15.06, 25, 35, 45, 55, 65)
    )
  })
  
  colNames <- reactive({c(input$grouping, "Col A", "Col B") })
  
  # summed_data <- reactive({
  #   filter(data(), Period_2 == "1") %>%
  #     group_by(!!sym(input$grouping)) %>%
  #     summarise(count = length(unique(ID)))
  # })
  
  summed_data <- reactive({
    data() %>%
      group_by(!!sym(input$grouping)) %>%
      select("ColA","ColB") %>%
      summarise(across(everything(), sum))
  })
  
  output$data <- renderTable(data())

  output$sums <- renderDT({
    summed_data() %>% 
      datatable(
        rownames = FALSE,
        colnames=colNames() # < add colNames()
        )
  })
  
}

shinyApp(ui, server)

问题出在您定义并添加到对 datatable 的调用中的 colNames()。我评论了那些行并且它起作用了。您的 sum data.frame 没有出现问题,因为此处 colnames 实际上存在于 data.frame 中,而 length(unique)) 中并非如此 data.frame.

library(dplyr)
library(DT)
library(shiny)
library(shinyWidgets)
library(tidyverse)

ui <-
  fluidPage(
    fluidRow(
      column(width = 8,
             h3("Data table:"),
             tableOutput("data"),
             h3("Sum the data table columns:"),
             
             radioButtons(
               inputId = "grouping",
               label = NULL,
               choiceNames = c("By period 1", "By period 2"),
               choiceValues = c("Period_1", "Period_2"),
               selected = "Period_1",
               inline = TRUE
             ),
             DT::dataTableOutput("sums")
      )
    )
  )

server <- function(input, output, session) {
  mydat <- reactive({
    data.frame(
      ID = c(115,115,111,88,120,16),
      Period_1 = c("2020-01", "2020-02", "2020-03", "2020-01", "2020-02", "2020-03"),
      Period_2 = c(1, 2, 3, 1, 1, 4),
      ColA = c(1000.01, 20, 30, 40, 50, 60),
      ColB = c(15.06, 25, 35, 45, 55, 65)
    )
  })
  
  # colNames <- reactive({c(input$grouping, "Col A", "Col B") })
  
  summed_data <- reactive({
    print(input$grouping)
    mydat() %>%
      dplyr::filter(Period_2 == 1) %>%
      dplyr::group_by(!!sym(input$grouping)) %>% 
      dplyr::summarise(count = length(unique(ID)))
  })
  
  # summed_data <- reactive({
  #   print(input$grouping)
  #   data() %>%
  #     group_by(across(all_of(input$grouping))) %>%
  #     select("ColA","ColB") %>%
  #     summarise(across(everything(), sum))
  # })
  
  output$data <- renderTable(mydat())
  
  output$sums <- renderDT({
    summed_data() %>% 
      datatable(
        rownames = FALSE,
        # colnames=colNames() # < add colNames()
      )
  })
  
}

shinyApp(ui, server)