2015-02-04 18 views
9

Ich habe folgendes data.table:auswerten Ausdruck 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 

Mein Ziel ist die folgende data.table zu erhalten:

> 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 

Ich habe versucht, die folgenden:

> 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 

Irgendeine Idee, wie ich die ans Spalte basierend auf dem Ausdruck in der 0 berechnen kannSpalte?

Antwort

12

Wenn Ihre tatsächlichen Ausdrücke beschreiben Anrufe vektorisiert Funktionen und sind oft jede wiederholt, dies effizienter sein kann, da sie analysiert nur und wertet jeden einzelnen Ausdruck einmal:

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

Wirklich, es gibt eine Reihe von Herausforderungen für die Vektorisierung in einem solchen Setup. eval erwartet nicht, dass er auf einem Vektor von Ausdrücken ausgeführt wird, noch ist er so eingerichtet, dass er standardmäßig über einen Vektor von Umgebungen iteriert. Hier definiere ich eine Hilfsfunktion, viel von der 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)] 

einzuwickeln, die

kehrt
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 

wie gewünscht. Beachten Sie, dass Sie die Parameter im Aufruf an calc() benennen müssen, damit sie weiß, welche Spalte welcher Variablen zugeordnet werden soll.

+0

Funktionale Programmierung FTW, große + 1 –