【问题标题】:Parse and Evaluate Column of String Expressions in R?在 R 中解析和评估字符串表达式的列?
【发布时间】:2019-08-04 18:27:02
【问题描述】:

如何解析和评估 R 中的字符串表达式列作为管道的一部分?

在下面的示例中,我生成了我想要的列,evaluated。但我知道这不是正确的方法。我尝试采用 tidyverse 方法。但我只是很困惑。

library(tidyverse)
df <- tibble(name = LETTERS[1:3], 
             to_evaluate = c("1-1+1", "iter+iter", "4*iter-1"), 
             evaluated = NA)
iter = 1
for (i in 1:nrow(df)) {
  df[i,"evaluated"] <- eval(parse(text=df$to_evaluate[[i]]))
}
print(df)
# # A tibble: 3 x 3
# name  to_evaluate evaluated
# <chr> <chr>           <dbl>
# 1 A     1-1+1               1
# 2 B     iter+iter           2
# 3 C     4*iter-1            3

作为管道的一部分,我尝试了:

df %>% mutate(evaluated = eval(parse(text=to_evaluate)))
df %>% mutate(evaluated = !!parse_exprs(to_evaluate))
df %>% mutate(evaluated = parse_exprs(to_evaluate))
df %>% mutate(evaluated = eval(parse_expr(to_evaluate)))
df %>% mutate(evaluated = parse_exprs(to_evaluate))
df %>% mutate(evaluated = eval(parse_exprs(to_evaluate)))
df %>% mutate(evaluated = eval_tidy(parse_exprs(to_evaluate)))

这些都不起作用。

【问题讨论】:

标签: r parsing dplyr eval rlang


【解决方案1】:

你可以试试:

df %>%
 rowwise() %>%
 mutate(iter = 1,
        evaluated = eval(parse(text = to_evaluate))) %>%
 select(-iter)

  name  to_evaluate evaluated
  <chr> <chr>           <dbl>
1 A     1-1+1               1
2 B     iter+iter           2
3 C     4*iter-1            3

按照这个逻辑,其他可能性也可以工作。使用rlang::parse_expr()

df %>%
 rowwise() %>%
 mutate(iter = 1,
        evaluated = eval(rlang::parse_expr(to_evaluate))) %>%
 select(-iter)

另一方面,我认为引用@Martin Mächler很重要:

(可能)唯一的连接是通过 parse(text = ....) 并且一切正常 R 程序员应该知道这很少是有效或安全的 表示构造表达式(或调用)。而是了解更多关于 替代(),报价(),可能还有使用的力量 do.call(替代,......).

【讨论】:

  • 您可以使用 mutate 和 pmap 来完成所有这些工作。 df %&gt;% mutate(evaluated = pmap_dbl(., function(name, to_evaluate, evaluated) eval(parse(text=to_evaluate))))
  • @rpolicastro 我认为值得单独发表一篇文章,请考虑发布它:)
  • 我会发布另一个答案,谢谢。不确定它是否与您的不同足以值得。
  • 这会稍微简化您的第二个解决方案:iter &lt;- 1; df %&gt;% rowwise() %&gt;% mutate(evaluated = eval(rlang::parse_expr(to_evaluate)))。无需在管道中定义iter
【解决方案2】:

这是一种稍微不同的方式,可以在 mutate 中执行所有操作。

df %>% mutate(
    evaluated = pmap_dbl(., function(name, to_evaluate, evaluated) 
                         eval(parse(text=to_evaluate)))
)

# A tibble: 3 x 3
  name  to_evaluate evaluated
  <chr> <chr>           <dbl>
1 A     1-1+1               1
2 B     iter+iter           2
3 C     4*iter-1            3

【讨论】:

    【解决方案3】:

    请注意,其他变量的值(例如您的情况下为iter=1)可以直接传递给eval()

    df %>% 
      mutate( evaluated = map_dbl(to_evaluate, ~eval(parse(text=.x), list(iter=1))) )
    

    一个优点是它会自动限制变量的范围,将其值保持在使用它的位置旁边。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-24
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      相关资源
      最近更新 更多