mutate and/or 汇总动态列数
mutate and/or summarise a dynamic number of columns
在上一个问题中,我想 case_when
使用动态数量的案例。解决方案是使用 parse_exprs
和 !!!
。我正在寻找与 mutate/summarise 具有动态列数的类似解决方案。
考虑以下数据集。
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))
假设我想对 g2
、g3
、g4
列求和。如果我知道这些是列名,那么这很简单,标准 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 包)。
过去有 mutate
和 summarise
(mutate_
和 summarise_
)的字符串版本,您可以将公式作为字符串传递给它们。但是这些已经被淘汰了,因为 rlang 方法现在是预期的方法。我在 Whosebug 上查看的相关问题没有使用 rlang 引用方法,因此不足以满足我的目的。
如何使用动态列数进行汇总(使用 rlang 方法)?
您的尝试给出了正确的答案,但没有按预期给出列名。
这是一种使用 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-stuff :
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))
自 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
在上一个问题中,我想 case_when
使用动态数量的案例。解决方案是使用 parse_exprs
和 !!!
。我正在寻找与 mutate/summarise 具有动态列数的类似解决方案。
考虑以下数据集。
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))
假设我想对 g2
、g3
、g4
列求和。如果我知道这些是列名,那么这很简单,标准 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 包)。
过去有 mutate
和 summarise
(mutate_
和 summarise_
)的字符串版本,您可以将公式作为字符串传递给它们。但是这些已经被淘汰了,因为 rlang 方法现在是预期的方法。我在 Whosebug 上查看的相关问题没有使用 rlang 引用方法,因此不足以满足我的目的。
如何使用动态列数进行汇总(使用 rlang 方法)?
您的尝试给出了正确的答案,但没有按预期给出列名。
这是一种使用 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-stuff :
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))
自 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