将data.table中的变量转换为公式

deb*_*ter 7 r data.table

我有一个示例 data.tabledata如下:

   VarName Formulae
1:       A      1+1
2:       B      A+3
3:       C     B*10
4:       D      A+C
5:       E      D/2
Run Code Online (Sandbox Code Playgroud)

我想将Formulae列转换为公式,以便输出可以变成这样:

  VarName Result
1:       A      2
2:       B      5
3:       C      50
4:       D      52
5:       E      26
Run Code Online (Sandbox Code Playgroud)

基本上,VarName列是变量名称,Formulae列是相应的公式。

A = 1+1
B = A+3
C = B*10
D = A+C
E = D/2
Run Code Online (Sandbox Code Playgroud)

我尝试过使用evalparse等函数data$VarName = eval(parse(text = "data$Formulae")),但是我无法获得所需的输出。

zx8*_*754 7

循环遍历VarName,将其替换为括号内的公式,然后计算:

res <- setNames(x$Formulae, x$VarName)

while(any(grepl(paste0(names(res), collapse = "|"), res))) {
  for(i in names(res)){
    res <- gsub(i, paste0("(", res[ i ], ")"), res, fixed = TRUE)
  }
}

#res, after replacements:
#                          A                          B 
#                      "1+1"                  "(1+1)+3" 
#                          C                          D 
#             "((1+1)+3)*10"     "(1+1)+(((1+1)+3)*10)" 
#                          E 
# "((1+1)+(((1+1)+3)*10))/2" 

# evaluate
sapply(res, function(i) eval(parse(text = i)))
#A  B  C  D  E 
#2  5 50 52 26 
Run Code Online (Sandbox Code Playgroud)

  • 为了使其更通用,您可以将 while 条件重新表述为:`any(grepl(paste0(names(res),collapse = "|"), res))` (3认同)

H 1*_*H 1 4

实现此目的的一种方法是转换Formulae为实际的单方面公式,然后转换为函数,然后在函数内部依次求值,lst()从而允许顺序构建对象。这依赖于框架的元编程功能tidyverse而不是data.table.

library(dplyr)
library(purrr)

df <- data.frame(VarName = LETTERS[1:5],
                 Formulae = c("1+1", "A+3", "B*10", "A+C", "D/2"))

lst(!!!map(set_names(df$Formulae, df$VarName),
           ~ quo(
             as_mapper(reformulate(.x))()
           )))
$A
[1] 2

$B
[1] 5

$C
[1] 50

$D
[1] 52

$E
[1] 26
Run Code Online (Sandbox Code Playgroud)

或者:

lst(!!!set_names(df$Formulae, df$VarName) %>% map(str2lang))
Run Code Online (Sandbox Code Playgroud)

正如下面的评论中所指出的,这些要求公式按顺序排列。