2015-02-04 8 views
9

Ho il seguente data.table:valutare l'espressione in R 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 

Il mio obiettivo è ottenere le seguenti 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 

ho provato la seguente:

> 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 

Qualche idea su come posso calcolare la colonna ans in base all'espressione nello 0 Colonna?

risposta

12

Se le espressioni attuali descrivono le chiamate alle funzioni vectorized e sono ripetuti molte volte ciascuno, questo può essere più efficiente, dal momento che analizza solo e valuta ogni espressione distinti una volta:

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 
6

Davvero, ci sono un sacco di sfide per la vettorizzazione in tale configurazione. eval non prevede di essere eseguito su un vettore di espressioni né è impostato per iterare su un vettore di ambienti per impostazione predefinita. Qui mi definisco una funzione di supporto per avvolgere gran dell'iterazione

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)] 

che restituisce

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 

, se lo desideri. Nota che dovrai chiamare i parametri nella chiamata a calc() in modo che sappia quale colonna mappare a quale variabile.

+0

programmazione funzionale FTW, grande + 1 –