2016-07-28 44 views
3

我有一个data.table和公式的列表,应用公式的列表至R data.table

DT <- data.table(A = c(1:3), B = c(3:1), C = c(4:6), D = (6:4)) 
l <- list(f1 = "A + B", f2 = "B + C", f3 = "C - D", f4 = "D/A") 

这可以通过

DT[, ":="(f1 = A + B, f2 = B + C, f3 = C - D, f4 = D/A)] 

for (i in 1:length(l)) { 
    DT[, eval(names(l)[i]) := eval(parse(text=l[[i]]))] 
} 
可以实现

有没有办法使用l中的信息来做到这一点,而不使用循环?

# some code 
DT 
# A B C D f1 f2 f3  f4 
# 1: 1 3 4 6 4 7 -2 6.000000 
# 2: 2 2 5 5 4 7 0 2.500000 
# 3: 3 1 6 4 4 7 2 1.333333 
+0

这里的循环有什么问题?并非所有循环都不好。 – dayne

+0

我只想知道是否有办法避免循环... –

+0

您可以使用'lapply'来避免循环遍历列,但通常使用循环并不总是一件大事,就像dayne所说的那样。首先,我猜你应该将这些表达式存储为表达式,而不是文本:'L = lapply(l,function(x)parse(text = x))''。然后,像DT [,\':= \'(名字(L),LAPLLY(L,EVAL,.SD))]'',这是有效的,但我不确定是否是犹太教。 – Frank

回答

10

如果你是手工构建l,而不是把它写像

L = quote(`:=`(f1 = A + B, f2 = B + C, f3 = C - D, f4 = D/A)) 

然后你可以使用它像

DT[, eval(L)] 

# A B C D f1 f2 f3  f4 
# 1: 1 3 4 6 4 7 -2 6.000000 
# 2: 2 2 5 5 4 7 0 2.500000 
# 3: 3 1 6 4 4 7 2 1.333333 

这是recommended practice from the FAQ,这也解释了......

quote()eval()像在其他语言中的宏。

+0

我想按组来评估所有这些公式,但data.table不允许我这样做。我应该怎么做?先谢谢你! –

+0

@ Nal-rA您可能需要发布一个新问题来澄清。当我尝试它时,它适用于我:'DT [,id:= c(1,1,2)]'then'DT [,eval(L),by = id] []' – Frank

+1

Thanks!看来我正在使用错误的方式。再次感谢你! –

2

这是超级邋遢,但可以使用callparsepaste创建表达式,然后调用该表达式:

library(data.table) 
DT <- data.table(A = c(1:3), B = c(3:1), C = c(4:6), D = (6:4)) 
l <- list(f1 = "A + B", f2 = "B + C", f3 = "C - D", f4 = "D/A") 
ncall <- call(":=", names(l), 
      parse(text = paste0("list(", paste(l, collapse = ","), ")"))) 
DT[ , eval(ncall)] 
DT 
# A B C D f1 f2 f3   f4 
# 1: 1 3 4 6 4 7 -2 6.00000000 
# 2: 2 2 5 5 4 7 0 2.50000000 
# 3: 3 1 6 4 4 7 2 1.33333333 
+0

您的方法可以按组来评估所有公式吗?谢谢! @dayne –

+0

您应该可以添加'k'项并按组进行评估,例如'DT [,eval(ncall),by = list(D)'。我没有明确地测试过这个,这个例子对分组没有意义,但是你可以自己测试一些代码。 – dayne