I have a sample data.table data
as below:
VarName Formulae
1: A 1 1
2: B A 3
3: C B*10
4: D A C
5: E D/2
I want to convert the Formulae
column into formulas, so that the output can become like:
VarName Result
1: A 2
2: B 5
3: C 50
4: D 52
5: E 26
Basically the VarName
column is the variable name and the Formulae
column is the corresponding formula.
A = 1 1
B = A 3
C = B*10
D = A C
E = D/2
I have tried using the eval
and parse
functions like data$VarName = eval(parse(text = "data$Formulae"))
, however I could not get the desired output.
CodePudding user response:
Loop through VarName replace them with Formulae within brackets, then evaluate:
res <- setNames(x$Formulae, x$VarName)
while(any(grepl("[A-Z]", 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
CodePudding user response:
One way to do this is to convert Formulae
to actual one-sided formulae and then functions which are in turn evaluated inside of lst()
which allows for the sequential building of objects. This relies on the metaprogramming functionality of the tidyverse
framework rather than 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(as.formula(reformulate(.x)))()
)))
$A
[1] 2
$B
[1] 5
$C
[1] 50
$D
[1] 52
$E
[1] 26
CodePudding user response:
Using apply
:
df <- data.frame("VarName"=c("X","Y"),"Formulae"=c("1 1","X 1"))
df$formulas <- apply(df,1,function(x)eval(parse(text = paste0(x["VarName"]," ~ ",x["Formulae"]))))
Using eval(parse(...))
structure was correct, but this should work properly. However, maybe someone will answer a cleaner proposition.
Take note that column "formulas" can not be a vector, so it is a list.
str(df)
'data.frame': 2 obs. of 3 variables:
$ VarName : chr "X" "Y"
$ Formulae: chr "1 1" "X 1"
$ formulas:List of 2
..$ :Class 'formula' language X ~ 1 1
.. .. ..- attr(*, ".Environment")=<environment: 0x000002933f8904a8>
..$ :Class 'formula' language Y ~ X 1
.. .. ..- attr(*, ".Environment")=<environment: 0x000002933fb6f3b8>
This can cause some headaches in dataframes usage. I suggest using mapping tools like purrr
instead of concatening everything into a dataframe in this case.