Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Evaluate expression in R data.table

Tags:

r

data.table

eval

I have the following data.table:

> dt = data.table(expr = c("a + b", "a - b", "a * b", "a / b"), a = c(1,2,3,4), b = c(5,6,7,8))
> dt
    expr a b
1: a + b 1 5
2: a - b 2 6
3: a * b 3 7
4: a / b 4 8

My aim is to get the following data.table:

> dt
    expr a b ans
1: a + b 1 5   6
2: a - b 2 6  -4
3: a * b 3 7  21
4: a / b 4 8 0.5

I tried the following:

> dt[, ans := eval(expr)]
Error in eval(expr, envir, enclos) : object 'expr' not found

> dt[, ans := eval(parse(text = expr))]
Error in parse(text = expr) : object 'expr' not found

Any idea how can I calculate the ans column based on the expression in the expr column?

like image 379
chengcj Avatar asked Feb 04 '15 17:02

chengcj


People also ask

What does eval mean in R?

Return value The eval() function returns the result of evaluating the object.

What is data table in R?

data.table is an R package that provides an enhanced version of data.frame s, which are the standard data structure for storing data in base R. In the Data section above, we already created a data.table using fread() . We can also create one using the data.table() function.

What are data table in coding?

Data tables contain data in a tabular form (it is the equivalent of two-dimensional arrays in programming). A data table contains rows and columns and each item stored in the data table can be retrieved through its unique row and column number.


2 Answers

If your actual expressions describe calls to vectorized functions and are repeated many times each, this may be more efficient, since it only parses and evaluates each distinct expression one time:

f <- function(e, .SD) eval(parse(text=e[1]), envir=.SD)
dt[, ans:=f(expr,.SD), by=expr, .SDcols=c("a", "b")]
#     expr a b  ans
# 1: a + b 1 5  6.0
# 2: a - b 2 6 -4.0
# 3: a * b 3 7 21.0
# 4: a / b 4 8  0.5
like image 197
Josh O'Brien Avatar answered Sep 21 '22 12:09

Josh O'Brien


Really, there are a bunch of challenges for vectorization in such a setup. eval doesn't expect to run on a vector of expressions nor is it set up to iterate over a vector of environments by default. Here I define a helper function to wrap much of the iteration

calc <- function(e, ...) {
   run<-function(x, ...) {
       eval(parse(text=x), list(...)) 
   }
   do.call("mapply", c(list(run, e), list(...)))
}

dt[, ans:=calc(expr,a=a,b=b)]

which returns

    expr a b  ans
1: a + b 1 5  6.0
2: a - b 2 6 -4.0
3: a * b 3 7 21.0
4: a / b 4 8  0.5

as desired. Note that you'll need to name the parameters in the call to calc() so it knows which column to map to which variable.

like image 34
MrFlick Avatar answered Sep 20 '22 12:09

MrFlick