data.table分别对数字和文本变量进行分组

the*_*ail 8 join r lapply data.table

我正在尝试简化这个data.table对数字和字符变量起作用的两阶段过程.例如 - 取第一个元素textvarsum每个数字变量.考虑这个小例子:

library(data.table)
dt <- data.table(grpvar=letters[c(1,1,2)], textvar=c("one","two","one"),
                 numvar=1:3, othernum=2:4)
dt
#   grpvar textvar numvar othernum
#1:      a     one      1        2
#2:      a     two      2        3
#3:      b     one      3        4
Run Code Online (Sandbox Code Playgroud)

现在我的第一个想法是嵌套.SD以将一个变量从lapply调用中删除,但我认为这有点复杂:

dt[, c(textvar=textvar[1], .SD[, lapply(.SD, sum), .SDcols=-c("textvar")]), by=grpvar]
#   grpvar textvar numvar othernum
#1:      a     one      3        5
#2:      b     one      3        4
Run Code Online (Sandbox Code Playgroud)

然后我想也许我可以单独分组并加入它们,但这似乎更糟糕:

dt[, .(textvar=textvar[1]), by=grpvar][ 
  dt[, lapply(.SD, sum), by=grpvar, .SDcols=-c("textvar")], on="grpvar" 
]
#   grpvar textvar numvar othernum
#1:      a     one      3        5
#2:      b     one      3        4
Run Code Online (Sandbox Code Playgroud)

是否有更简单的结构可以绕过嵌套.SD或连接?我觉得我忽略了一些基本的东西.

Aru*_*run 8

j在-argument data.table是(故意)相当灵活.我们需要记住的是:

只要j返回一个列表,列表中的每个元素都将成为结果data.table中的一列.

使用的事实c(list, list)list,我们可以构建表达如下:

dt[, c(textvar = textvar[1L], lapply(.SD, sum)), # select/compute all cols necessary
      .SDcols = numvar:othernum,                 # provide .SD's columns 
      by = grpvar]                               # group by 'grpvar'
#    grpvar textvar numvar othernum
# 1:      a     one      3        5
# 2:      b     one      3        4
Run Code Online (Sandbox Code Playgroud)

在这里,我没有包装第一个表达式,list()因为textvar[1L]返回一个长度= 1的向量..即,identical(c(1, list(2, 3)), c(list(1), list(2,3)))TRUE.

请注意,这只能来自v1.9.7.该错误最近刚刚在当前的开发版本中得到修复.