使用带逗号的as.formula

Int*_*ion 4 r dplyr tidyeval

我想从用户那里动态获取条件,所以我构建了一个闪亮的应用程序,可以从输入字段中获取它们。问题是as.formula不适用于带有逗号的字符向量(没有效果的话)。

码:

all_conditions = 
  "condition1 ~ 0,
   condition2 ~ 1,
   condition3 ~ 2"

 my_dataset %>% group_by(id) %>%
  summarise(FLAG = case_when(
      as.formula(all_conditions) )
   )
Run Code Online (Sandbox Code Playgroud)

我得到:

评估错误:: 2:100:意外的','

我尝试使用paste和转义逗号没有成功。

Lio*_*nry 5

您收集输入的方式不太实用。您的问题是您试图解析如下代码:

var1, var2, var3
Run Code Online (Sandbox Code Playgroud)

尝试在R控制台中键入该命令,您将得到相同的错误:

#> Error: unexpected ',' in "var1,"
Run Code Online (Sandbox Code Playgroud)

因此,首先重构代码,以便将输入收集为两个向量:

cnds <- c("condition1", "condition2", "condition3")
vals <- c("1", "2", "3")
Run Code Online (Sandbox Code Playgroud)

现在,您有两种选择可以将这些字符串转换为R代码:解析或创建符号。当您期望使用任意R代码时,可以使用前者;而在期望变量或列名称时,可以使用后者。您能发现差异吗?

rlang::parse_exprs(c("foo", "bar()", "100"))
#> [[1]]
#> foo
#>
#> [[2]]
#> bar()
#>
#> [[3]]
#> [1] 100

rlang::syms(c("foo", "bar()", "100"))
#> [[1]]
#> foo
#>
#> [[2]]
#> `bar()`
#>
#> [[3]]
#> `100`
Run Code Online (Sandbox Code Playgroud)

在您的情况下,您可能需要解析,因为条件将是R代码。因此,让我们首先解析两个向量:

cnds <- map(cnds, rlang::parse_expr)
vals <- map(vals, rlang::parse_expr)
Run Code Online (Sandbox Code Playgroud)

我映射parse_expr()而不是使用复数版本,parse_exprs()因为后者可以返回比其输入更长的列表。例如,parse_exprs(c("foo; bar", "baz; bam"))将2个字符串转换为4个表达式的列表。parse_expr()如果一个字符串包含多个表达式,则返回错误,因此在本例中更健壮。

现在,我们可以映射LHS和RHS的这两个列表并创建公式。一种简单的方法是通过取消引用每个LHS及其对应的RHS来使用准引用创建公式:

fs <- map2(cnds, vals, function(c, v) rlang::expr(!!c ~ !!v))
Run Code Online (Sandbox Code Playgroud)

结果是可以拼接为case_when()以下公式表达式的列表:

data %>% mutate(result = case_when(!!!fs))
Run Code Online (Sandbox Code Playgroud)

用于rlang::qq_show()确切地查看拼接取消引用在做什么:

rlang::qq_show(mutate(result = case_when(!!!fs)))
#> mutate(result = case_when(condition1 ~ 1, condition2 ~2, condition3 ~ 3))
Run Code Online (Sandbox Code Playgroud)