2016-07-28 41 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