在上一个问题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()以某种方式将多行传递给函数。为什么会这样?
答案 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
参数。这也有效,但速度较慢。一般来说,如果你可以矢量化你应该。