在自定义 dplyr 函数中使用列向量

Use vector of columns in custom dplyr function

我正在尝试使用 tidyverse 创建一个函数,该函数允许我获取列名向量(class 因子),计算有多少观察值满足特定条件(值 ==“ yes"), mutate() 并使用此总和创建新列,以便稍后汇总数据。

我已经编写了一个可以对单个列执行此操作的函数,但我希望能够使用 all_of() 语法将任意长度的列名向量传递给该函数。当我尝试这个时,我得到一个与向量同名的新列(包括我的 _count 后缀)而不是向量中的值。

这与 类似,但我想传递一个长度 > 1 的向量。

我想我可能需要使用 dplyr 中的 (. . .) 选项和一些更多的 rlang,但我还没有找到正确的组合。由于 NSE,当我用 (...) 代替 objective 时,该功能不起作用。我还尝试了 rlang::as_name()rlang::get_env() 的变体。有一个过时的工作簿也使用了 purrr::map(),但我没有运气在这里实施它。

我得到错误:找不到列 x。 或错误:Promise 已被强制

这是一个带有数据的可重现示例

dat <- tibble(category = rep(letters[1:10], 2),
              intake = factor(c(rep("no", 12), rep("yes", 8))), 
              outtake = factor(c(rep("yes", 11), rep("no", 9))),
              pretake = factor(c(rep(c("no", "yes"), 10))))

yessum <- function(.data, objective) {
  .data %>%
    dplyr::mutate("{{objective}}_count" := sum(
      ifelse(
        unlist(!!rlang::ensym(objective)) == "yes", 1, 0)))
}

dat %>%
  group_by(category) %>%
  yessum(intake)

我希望能够将某些列名的向量传递给 yessum 并接收一组新列,就像 intake_new 但命名为 outtake_newpretake_new.

这是我尝试时目前发生的情况:

vars <- c("intake", "outtake", "pretake")

dat %>%
  group_by(category) %>%
  yessum(vars)

欢迎任何帮助!

您不一定需要该函数,因为您可以只 mutate across 列并获取每个类别的总和。

library(tidyverse)

dat %>%
  group_by(category) %>%
  mutate(across(ends_with("take"), .fns = list(count = ~sum(. == "yes"))))

或者如果你有一个长列表,那么你可以在across语句中直接使用vars

vars <- c("intake", "outtake", "pretake")

dat %>%
  group_by(category) %>%
  mutate(across(vars, .fns = list(count = ~sum(. == "yes"))))

输出

  category intake outtake pretake intake_count outtake_count pretake_count
   <chr>    <fct>  <fct>   <fct>          <int>         <int>         <int>
 1 a        no     yes     no                 0             2             0
 2 b        no     yes     yes                0             1             2
 3 c        no     yes     no                 1             1             0
 4 d        no     yes     yes                1             1             2
 5 e        no     yes     no                 1             1             0
 6 f        no     yes     yes                1             1             2
 7 g        no     yes     no                 1             1             0
 8 h        no     yes     yes                1             1             2
 9 i        no     yes     no                 1             1             0
10 j        no     yes     yes                1             1             2
11 a        no     yes     no                 0             2             0
12 b        no     no      yes                0             1             2
13 c        yes    no      no                 1             1             0
14 d        yes    no      yes                1             1             2
15 e        yes    no      no                 1             1             0
16 f        yes    no      yes                1             1             2
17 g        yes    no      no                 1             1             0
18 h        yes    no      yes                1             1             2
19 i        yes    no      no                 1             1             0
20 j        yes    no      yes                1             1             2