使用条件函数在data.table()中分配多个列

时间:2014-02-09 18:21:16

标签: r data.table

在上一个问题Return a list in dplyr mutate()中,虽然dlpyr无法在版本0.2中创建来自函数返回的向量的新变量,但是数据可以使用语法 - :

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 个答案:

答案 0 :(得分:4)

罗恩,这是预期的行为。 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参数。这也有效,但速度较慢。一般来说,如果你可以矢量化你应该。