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]
足够了。
我正在使用 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]
足够了。