【问题标题】:mutate and/or summarise a dynamic number of columns变异和/或汇总动态列数
【发布时间】:2020-12-20 05:44:32
【问题描述】:

在上一个问题中,我想以动态数量的案例执行case_when。解决方案是使用parse_exprs!!!。我正在寻找一种类似的解决方案来使用动态列数进行变异/汇总。

考虑以下数据集。

library(dplyr)
library(rlang)
data(mtcars)
mtcars = mtcars %>%
  mutate(g2 = ifelse(gear == 2, 1, 0),
         g3 = ifelse(gear == 3, 1, 0),
         g4 = ifelse(gear == 4, 1, 0))

假设我想对 g2g3g4 列求和。如果我知道这些是列名,那么这很简单,标准 dplyr:

answer = mtcars %>%
  summarise(sum_g2 = sum(g2),
            sum_g3 = sum(g3),
            sum_g4 = sum(g4))

但是假设我不知道有多少列,或者它们的确切名称。相反,我有一个包含我关心的所有列名的向量。按照我以前的方法接受的答案中的逻辑,我会使用:

columns_to_sum = c("g2","g3","g4")

formulas = paste0("sum_",columns_to_sum," = sum(",columns_to_sum,")")

answer = mtcars %>%
  summarise(!!!parse_exprs(formulas))

如果这确实有效,那么无论columns_to_sum 中作为输入提供的列名如何,我都应该收到相应列的总和。但是,这是行不通的。而不是名为 sum_g2 的列包含 sum(g2) 我得到一个名为 "sum_g2 = sum(g2)" 的列,并且该列中的每个值都是零。

鉴于我可以将公式传递给case_when,看来我应该能够将公式传递给summarise(同样的想法也应该适用于mutate,因为它们都使用rlang包)。

过去有mutatesummarisemutate_summarise_)的字符串版本,您可以将公式作为字符串传递。但是这些已经被淘汰,因为 rlang 方法现在是预期的方法。我在 Stackoverflow 上查看的相关问题没有使用 rlang 引用方法,因此不足以满足我的目的。

如何使用动态列数进行汇总(使用 rlang 方法)?

【问题讨论】:

    标签: r dplyr rlang


    【解决方案1】:

    dplyr 1.0.0 之后的一个选项可能是:

    mtcars %>%
     summarise(across(all_of(columns_to_sum), sum, .names = "sum_{col}"))
    
      sum_g2 sum_g3 sum_g4
    1      0     15     12
    

    【讨论】:

    • 这也适用于不在columns_to_sum 中的其他变量,例如:summarise(num = n(), across(all_of(cols), sum, .names = "sum_{cols}")
    • 但请注意 .names = cols 会产生错误。您的输出列需要与输入列不同的名称。
    【解决方案2】:

    您的尝试给出了正确答案,但未按预期给出列名。

    这是一种使用map 来获取正确名称的方法:

    library(dplyr)
    library(rlang)
    library(purrr)
    
    map_dfc(columns_to_sum, ~mtcars %>% 
                             summarise(!!paste0('sum_', .x) := sum(!!sym(.x))))
    
    #  sum_g2 sum_g3 sum_g4
    #1      0     15     12
    

    您也可以使用这种简单的基本 R 方法,而无需任何 NSE 材料:

    setNames(data.frame(t(colSums(mtcars[columns_to_sum]))), 
             paste0('sum_', columns_to_sum))
    

    dplyr 方式相同:

    mtcars %>%
      summarise(across(all_of(columns_to_sum), sum)) %>%
      set_names(paste0('sum_', columns_to_sum))
    

    【讨论】:

      猜你喜欢
      • 2020-01-16
      • 1970-01-01
      • 1970-01-01
      • 2021-01-08
      • 2022-08-18
      • 1970-01-01
      • 1970-01-01
      • 2018-11-05
      • 2021-10-03
      相关资源
      最近更新 更多