首页 > 解决方案 > data.table 中的 Computed `by` 子句

问题描述

by子句可以是用于计算分组列的表达式列表。它也可以是一个表达式,计算结果为列名的字符向量,如果它包含在eval(…). 但是,如果您想以编程方式确定存在哪些分组变量以及存在多少个分组变量,并且并非所有这些分组变量都是预先存在的列,该怎么办?你会认为它是可行的eval, quote, 或bquote我无法弄清楚。

作为一个简单但人为的示例,假设您要编写一个像这样工作的函数:

f = function(x)
  {d = as.data.table(mtcars)
   if (x)
       d[, by = .(mycyl = cyl + 1, myv = vs + 1),
           mean(wt)]
   else
       d[, by = .(mycyl = cyl + 1),
           mean(wt)]}

但看起来像这样:

f = function(x)
  {d = as.data.table(mtcars)
   d[, by = c(.(mycyl = cyl + 1), (if (x) .(myv = vs + 1) else NULL)),
       mean(wt)]}

这怎么可能实现?如所写,第二个版本产生Error in .(mycyl = cyl + 1) : could not find function ".". 如果.替换为list,则生成Error in eval(bysub, parent.frame(), parent.frame()) : object 'cyl' not found

标签: rdata.table

解决方案


你其实很亲近。使用list代替.

library(data.table)

d = as.data.table(mtcars)

d[, mean(wt), by = .(mycyl = cyl + 1, myv = vs + 1),]
#>    mycyl myv       V1
#> 1:     7   1 2.755000
#> 2:     5   2 2.300300
#> 3:     7   2 3.388750
#> 4:     9   1 3.999214
#> 5:     5   1 2.140000
d[, mean(wt), by = .(mycyl = cyl + 1)]
#>    mycyl       V1
#> 1:     7 3.117143
#> 2:     5 2.285727
#> 3:     9 3.999214

x = FALSE
d[, mean(wt), by = if(x) list(mycyl = cyl + 1) else list(mycyl = cyl + 1, myv = vs + 1)]
#>    mycyl myv       V1
#> 1:     7   1 2.755000
#> 2:     5   2 2.300300
#> 3:     7   2 3.388750
#> 4:     9   1 3.999214
#> 5:     5   1 2.140000

x = TRUE
d[, mean(wt), by = if(x) list(mycyl = cyl + 1) else list(mycyl = cyl + 1, myv = vs + 1)]
#>    mycyl       V1
#> 1:     7 3.117143
#> 2:     5 2.285727
#> 3:     9 3.999214

推荐阅读