data.table: lapply 具有多列输出的函数

data.table: lapply a function with multicolumn output

我正在使用 Hmisc 包中的一个函数 smean.cl.normal,它 returns 一个具有 3 个值的向量:均值、下限和上限 CI。当我在有 2 个组的 data.table 上使用它时,我得到 2 列和 6 行。有没有办法获得对应于 2 组的两行和每个函数输出的单独列的结果,即平均值和 CIs?

require(Hmisc)
require(data.table)

dt = data.table(x = rnorm(100),
                gr = rep(c('A', 'B'), each = 50))

dt[, lapply(.SD, smean.cl.normal), by = gr, .SDcols = "x"]

输出:

   gr           x
1:  A -0.07916335
2:  A -0.33656667
3:  A  0.17823998
4:  B -0.02745333
5:  B -0.32950607
6:  B  0.27459941

期望的输出:

   gr        Mean         Lower         Upper
1:  A -0.07916335   -0.33656667    0.17823998
2:  B -0.02745333   -0.32950607    0.27459941

DT[i,j,by] 中的 j 参数需要一个列表,所以使用 as.list:

dt[, 
  Reduce(c, lapply(.SD, function(x) as.list(smean.cl.normal(x))))
, by = gr, .SDcols = "x"]

#    gr       Mean      Lower     Upper
# 1:  A  0.1032966 -0.1899466 0.3965398
# 2:  B -0.1437617 -0.4261330 0.1386096

c(L1, L2, L3) 是列表的组合方式,因此 Reduce(c, List_o_Lists) 可以在您的 .SDcols 包含的不仅仅是 x 的情况下发挥作用。我想 do.call(c, List_o_Lists) 应该也可以。


评论

由于几个原因,这是非常低效的。打开 verbose=TRUE 可以看到 data.table 不喜欢在 j:

中获取命名列表

The result of j is a named list. It's very inefficient to create the same names over and over again for each group. When j=list(...), any names are detected, removed and put back after grouping has completed, for efficiency. Using j=transform(), for example, prevents that speedup (consider changing to :=). This message may be upgraded to warning in future.

此外,您还错过了 mean 的 group-optimized 版本以及可能用于构建结果的其他函数。不过,这对您的 use-case 来说可能不是什么大问题。


当您仅将其应用于单个值列时,只需:

dt[, as.list(smean.cl.normal(x)), by = gr]

足够了。