2014-02-09 19 views
1

在上一个问题Return a list in dplyr mutate()中,有人说,虽然dlpyr不能在版本0.2中从函数返回的向量创建新变量,但data.table()可以使用语法 - :使用条件函数在data.table()中分配多列

it[, c(paste0("V", 4:5)) := myfun(V2, V3)] 

如果从这个问题的功能myfun被更改为 - :

myfun = function(arg1,arg2) { 


if (arg1 > arg2) { 
temp1 = arg1 + arg2 
temp2 = arg1 - arg2 } 
else { 
temp1 = arg1 * arg2 
temp2 = arg1/arg2 } 
list(temp1,temp2) 

} 

上面贴的解决方案返回警告 - :

it = data.table(c("a","a","b","b","c"),c(1,2,3,4,5), c(2,3,4,2,2)) 
it[, c(paste0("V", 4:5)) := myfun(V2, V3)] 

Warning message: 
In if (arg1 > arg2) { : 
    the condition has length > 1 and only the first element will be used 

这意味着以某种方式data.table()传递多个单行到函数。为什么会发生?

+1

该警告来自您的功能。只要做了myfun(它$ V2,$ V3)'就会发出同样的警告。这是因为您在执行'arg1> arg2'时比较了两个向量(长度> 1)。所以,它只需要第一个值(并提供警告)。 – Arun

回答

3

罗恩,这是预期的行为。 data.table始终传递完整列(除非使用by,在这种情况下,您将获得与每个子组对应的列的部分)。为了解决这个问题,你需要向量化你的函数:

myfun2 = function(arg1,arg2) { 
    temp1 <- ifelse(arg1 > arg2, arg1 + arg2, arg1 * arg2) 
    temp2 <- ifelse(arg1 > arg2, arg1 - arg2, arg1/arg2) 
    list(temp1,temp2) 
} 

我这样做是在这里使用ifelse,而不是if/else。然后,它的工作原理:

it = data.table(c("a","a","b","b","c"),c(1,2,3,4,5), c(2,3,4,2,2)) 
it[, c(paste0("V", 4:5)) := myfun2(V2, V3)] 
it 
# V1 V2 V3 V4  V5 
# 1: a 1 2 2 0.5000000 
# 2: a 2 3 6 0.6666667 
# 3: b 3 4 12 0.7500000 
# 4: b 4 2 6 2.0000000 
# 5: c 5 2 7 3.0000000 

另一种选择,如果你不想修改你的功能,更是打破了data.table成一个行组。我们通过使向量by具有用于在data.table各行的不同值执行此操作(使得每一行是一个组):

it[, c(paste0("V", 4:5)) := myfun(V2, V3), by=1:nrow(it)] 

通知的by参数。这也行得通,但速度较慢。一般来说,如果你可以矢量化你应该。

相关问题