假设我有以下数据结构:
library(dplyr)
d <- tibble(x = paste0("x", 1:3),
op = c("f", "g", "h"),
y = paste0("y", 1:3),
res = paste0("z", 1:3))
我想创建一个cmd
包含未评估调用的新列,它最终应如下所示:
(D <- d %>%
mutate(cmd = list(quote(z1 <- f(x1, y1)),
quote(z2 <- g(x2, y2)),
quote(z3 <- h(x3, y3)))))
# # A tibble: 3 × 5
# x op y res cmd
# <chr> <chr> <chr> <chr> <list>
# 1 x1 f y1 z1 <language>
# 2 x2 g y2 z2 <language>
# 3 x3 h y3 z3 <language>
但我当然不想对这些行进行硬编码,而是想从相应的行中提取这些值d
,但我没有成功:
d %>%
rowwise() %>%
mutate(cmd = list(expr(!!sym(res) <- !!sym(op)(!!sym(x), !!sym(y)))))
结果:
Error: object 'res' not found
我将如何实现这个目标?
NB cmd
最终将在定义参数和函数的环境中进行评估,因此从概念上讲类似于:
e <- list2env(list(x1 = 1, x2 = 2, x3 = 3, y1 = 2, y2 = 2, y3 = 3,
f = \(x, y) x + y, g = \(x, y) x - y, h = \(x, y) x * y))
eval(D$cmd[[1]], e)
e$z1
# [1] 3
一种可能性是回到替代方案:
但我仍在寻找 tidyverse 解决方案。
在 Base R 中你可以执行以下操作:
这对于评论来说太长了,因此将其作为答案发布。它可能对找到这个问题的人有用。
我认为您的设计存在问题。标准建议似乎适用:不要在环境中创建编号变量。使用向量和列表。
这只是示例用法。当然,您可以像在 中一样根据元信息对向量/列表进行子集化
d
。关键是您不需要构造调用(当然也不需要调用<-
)并像您建议的那样对其进行评估。您已经获得了很好的 R 基础答案,因此我将重点介绍
tidyverse
,它似乎发生了很大变化。 2017 年的这个问题与您的问题的一部分(构建分配调用)有关,但接受的答案建议使用rlang::lang()
,现在已弃用 ,取而代之的是rlang::call2()
。 因此,我认为tidyverse
现在推荐的方法是这样的:这将为您提供
cmd
如下所示的一列:根据您的问题的环境中的需要进行评估:
我们还可以看到这将分配给所需的变量
e
:由于输入列都是字符串,因此首先使用字符串操作,然后在最后转换为 R 表达式似乎更有意义。在这种情况下,
glue
可以按如下所示使用:更新
已
parse_exprs
按照parse_expr
@SamR 的建议用来代替消除rowwise
。