【问题标题】:Assigning multiple columns in data.table() with conditional function使用条件函数在 data.table() 中分配多列
【发布时间】:2014-02-09 18:21:16
【问题描述】:

在上一个问题Return a list in dplyr mutate() 中明确指出,虽然 dlpyr 在 0.2 版中不能从函数返回的向量创建新变量,但 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() 以某种方式将不止一行传递给函数。为什么会出现这种情况?

【问题讨论】:

  • 该警告来自您的函数。只是做myfun(it$V2, it$V3) 会给出同样的警告。这是因为您在执行arg1 > arg2 时正在比较两个向量(长度> 1)。因此,它只需要第一个值(并提供警告)。

标签: r data.table


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 2012-07-25
    • 2018-05-10
    • 2019-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-29
    • 2013-06-01
    • 2022-01-13
    相关资源
    最近更新 更多