从一个函数计算多列并将它们添加到数据框中。

6
我希望从一个 data.frame 的列上返回多个结果,并将这些新列与其他简单计算一起添加到同一个 data.frame 中。
举个简单的例子,如果我想要得到 sin 函数的积分值和绝对误差,以及积分区间的中点:
df <- data.frame(Lower = c(1,2,3), Upper = c(2,3,4))
setDT(df)
getIntegral <- function(l, u) {
  n <- integrate(sin, mean(l), mean(u))
  list(Value=n$value, Error=n$abs.error)
}
df[,
   c('Value', 'Error', 'Mid') := {
     n <- getIntegral(Lower, Upper)
     list(n$Value,
          n$Error,
          (Lower+Upper)/2)
   }]
df
   Lower Upper     Value        Error Mid
1:     1     2 0.5738457 6.370967e-15 1.5
2:     2     3 0.5738457 6.370967e-15 2.5
3:     3     4 0.5738457 6.370967e-15 3.5

我不太喜欢我的方法,因为将新列的名称与分配给它们的值分开使得阅读起来很困难。有什么更好的方法可以完成这个任务吗?这是一个长数据处理链的一部分,所以我不想在外部创建临时变量,所以我希望使用 data.tabledplyr 单独提供解决方案。


你是说你不喜欢data.table的语法吗? - jlhoward
你的意思是这样吗?setDT(df)[,":="(Value=getIntegral(Lower,Upper)$Value, Error=getIntegral(Lower,Upper)$Error, Mid =(Lower+Upper)/2)] - jlhoward
或者也许是这样的?setDT(df)[,c("Value","Rrror","Mid"):= with(getIntegral(Lower,Upper),list(Value,Error,(Lower+Upper)/2))] - jlhoward
@jlhoward,我想要类似于setDT(df)[,":="(Value=getIntegral(Lower,Upper)$Value, Error=getIntegral(Lower,Upper)$Error, Mid =(Lower+Upper)/2)]的东西,但我不想运行两次getIntegral - user3684014
那就用第一种方法。或者,您可以更改函数以返回一个命名列表,其中包含所有三个值(Value、Error 和 Mid),然后只需使用 setDT(df)[,getIntegral(Lower,Upper),by=list(Lower,Upper)] - jlhoward
@jlhoward,这只是一个简化的例子,在我的实际用例中有许多这样的计算组合,为每个新的所需输出组合创建新函数太费力了。 - user3684014
1个回答

8

右手边应该是一个值列表,列表中的每个元素都会被转换为一列(必要时进行循环利用)。

您的函数已经返回一个长度为 1 的列表,而 (Lower+Upper)/2 返回一个包含 3 个值的向量(此处)。为了返回一个列表,可以使用函数 c(),如下所示:

df[, c('Value', 'Error', 'Mid') := c(getIntegral(Lower, Upper), list((Lower+Upper)/2))]
#    Lower Upper     Value        Error Mid
# 1:     1     2 0.5738457 6.370967e-15 1.5
# 2:     2     3 0.5738457 6.370967e-15 2.5
# 3:     3     4 0.5738457 6.370967e-15 3.5

这是利用了 c(list, list) 会返回一个连接后的列表的事实。

正如@jlhoward在问题评论中提到的那样,我是否可以像setDT(df)[,":="(Value=getIntegral(Lower,Upper)$Value, Error=getIntegral(Lower,Upper)$Error, Mid =(Lower+Upper)/2)]这样做,而不必运行两次getIntegral?我希望列的名称和分配给它们的值更接近,因为我有一个很长的计算列表。 - user3684014
不,我不认为那是可能的。 - Arun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接