2015-02-04 18 views
9

Tôi đã sau data.table:Đánh giá biểu hiện trong 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 

Mục tiêu của tôi là để có được những điều sau 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 

tôi thử như sau:

> 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 

Bất kỳ ý tưởng làm thế nào tôi có thể tính toán cột ans dựa trên biểu thức trong expr cột?

Trả lời

12

Nếu biểu thức thực tế của bạn mô tả các cuộc gọi đến các chức năng vectorized và được lặp đi lặp lại nhiều lần mỗi, điều này có thể hiệu quả hơn, vì nó chỉ phân tích và đánh giá mỗi biểu hiện rõ rệt một lần:

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

Thực sự, có rất nhiều thách thức đối với việc vectơ hóa trong một thiết lập như vậy. eval không mong đợi để chạy trên một vector của các biểu thức cũng không được thiết lập để lặp qua một vector của môi trường theo mặc định. Ở đây tôi định nghĩa một hàm helper để bọc phần lớn lặp

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

trả về

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 

như mong muốn. Lưu ý rằng bạn sẽ cần phải đặt tên cho các tham số trong cuộc gọi đến calc() để nó biết cột nào sẽ ánh xạ tới biến nào.

+0

lập trình chức năng FTW, lớn + 1 –