R rlang: call_args 在 dplyr::mutate

R rlang: call_args in dplyr::mutate

我在 dplyr::mutate 中使用 rlang::call_args 时出错。我已经找到了不使用 dplyr::mutate 的解决方法。我的目标是找出错误的真正原因并学习一起使用 rlangdplyr 的正确方法。

我有一个数据框,其中一列存储函数调用,例如

df <- tibble::tibble(
  `call` = c(expr(f1(a=1, b=2)), expr(f2(x=5,y=6)), expr(f3(m=9, n=10)))
)

# > df
# # A tibble: 3 x 1
#   call      
#   <list>    
# 1 <language>
# 2 <language>
# 3 <language>

我想用 rlang::call_args 为参数列表创建一个新列。预期的输出应该像

# # A tibble: 3 x 2
#  call       args            
#  <list>     <list>          
# 1 <language> <named list [2]>
# 2 <language> <named list [2]>
# 3 <language> <named list [2]>

使用包含函数参数的命名列表作为 args 列中的每一行:

> expected_output$args[[1]]
# $a
# [1] 1

# $b
# [1] 2 

> expected_output$args[[2]]
# $x
# [1] 5

# $y
# [1] 6 

等等。

当我尝试 rlang::call_argsdplyr::mutate 时,出现错误提示我输入不是引用调用:

> df %>% mutate(args = rlang::call_args(call))
Error: Problem with `mutate()` input `args`.
x `call` must be a quoted call
ℹ Input `args` is `rlang::call_args(call)`.
Run `rlang::last_error()` to see where the error occurred.
> rlang::last_error()
<error/dplyr:::mutate_error>
Problem with `mutate()` input `args`.
x `call` must be a quoted call
ℹ Input `args` is `rlang::call_args(call)`.
Backtrace:
Run `rlang::last_trace()` to see the full context.
> rlang::last_trace()
<error/dplyr:::mutate_error>
Problem with `mutate()` input `args`.
x `call` must be a quoted call
ℹ Input `args` is `rlang::call_args(call)`.
Backtrace:
     █
  1. ├─df %>% mutate(args = rlang::call_args(call))
  2. ├─dplyr::mutate(., args = rlang::call_args(call))
  3. ├─dplyr:::mutate.data.frame(., args = rlang::call_args(call))
  4. │ └─dplyr:::mutate_cols(.data, ...)
  5. │   ├─base::withCallingHandlers(...)
  6. │   └─mask$eval_all_mutate(dots[[i]])
  7. ├─rlang::call_args(call)
  8. │ └─rlang:::abort_call_input_type("call")
  9. │   └─rlang::abort(sprintf("`%s` must be a quoted call", arg))
 10. │     └─rlang:::signal_abort(cnd)
 11. │       └─base::signalCondition(cnd)
 12. └─(function (e) ...

我检查了df$call的元素并确认所有元素都是调用对象。

> all(sapply(df$call, rlang::is_call))
# [1] TRUE

我不确定 x 'call' must be a quoted call 在错误消息中的确切含义。我认为 dplyr::mutate 中的函数参数应该被自动视为引用表达式,因为我们可以做类似

的事情
dplyr::mutate(df, NEWVAR = tolower(OLDVAR))

没有找到对象 'OLDVAR' 的错误。

我已经找到解决方法:

> tibble::as_tibble(list(call = df$call, args = lapply(df$call, call_args)))
# # A tibble: 3 x 2
#  call       args            
#  <list>     <list>          
# 1 <language> <named list [2]>
# 2 <language> <named list [2]>
# 3 <language> <named list [2]>

对于这个线程,我不是在寻求另一种方法来解决这个特定问题,而是在寻找对 dplyr::mutate 错误的清晰理解,并学习将 dplyr 与 [= 一起使用的正确方法23=] 函数。

有两个潜在的问题,不是rlang特有的:

  1. call_args() 未向量化(如另一条评论中所述),这意味着它一次只能处理一个调用,而不是列表或调用向量。写作 df %>% mutate(args = call_args(call)) 等同于 df$args = call_args(df$call),其中 df$call 是一个包含 3 个表达式的向量。尝试一下,您会遇到与您描述的相同的错误。可能的解决方案是使用 dplyr::rowwise()

  2. call_args() returns 一个列表,长度可能 > 1。要在行向变异中使用它,您需要将其输出包装在显式 list()。否则 dplyr 会抱怨您正在尝试将 2 个值分配给 1 行数据框中的变量。

解决方案:

df = df %>% rowwise() %>% mutate(args = list(rlang::call_args(call))) %>% ungroup()
df$args

注意:您使用 tibble 提出的 lapply() 方法也可以使用 mutate 来完成,而无需按行。不过,也许有点 dplyr-ish?

df = df %>% mutate(args = lapply(call, rlang::call_args))
df$args