这非常类似于将常用函数应用于data.table
uning .SDcols
answered thoroughly here的多列的问题。
不同之处在于我想同时在不属于.SD
子集的另一列上应用不同的函数。我在下面发布了一个简单的例子来展示我尝试解决问题:
dt = data.table(grp = sample(letters[1:3],100, replace = TRUE),
v1 = rnorm(100),
v2 = rnorm(100),
v3 = rnorm(100))
sd.cols = c("v2", "v3")
dt.out = dt[, list(v1 = sum(v1), lapply(.SD,mean)), by = grp, .SDcols = sd.cols]
产生以下错误:
Error in `[.data.table`(dt, , list(v1 = sum(v1), lapply(.SD, mean)), by = grp,
: object 'v1' not found
现在这是有道理的,因为v1
列不包含在必须首先评估的列子集中。所以我通过将其包含在我的列子集中进一步探索:
sd.cols = c("v1","v2", "v3")
dt.out = dt[, list(sum(v1), lapply(.SD,mean)), by = grp, .SDcols = sd.cols]
现在这不会导致错误,但它提供了一个包含9行(对于3组)的答案,其中总和在V1
列中重复三次,并且所有3列的均值(按预期但不需要)放在V2
中,如下所示:
> dt.out
grp V1 V2
1: c -1.070608 -0.0486639841313638
2: c -1.070608 -0.178154270921521
3: c -1.070608 -0.137625003604012
4: b -2.782252 -0.0794929150464099
5: b -2.782252 -0.149529237116445
6: b -2.782252 0.199925178109264
7: a 6.091355 0.141659419355985
8: a 6.091355 -0.0272192037753071
9: a 6.091355 0.00815760216214876
使用两个步骤解决方法
显然,可以通过计算列的子集的mean
按组并将其连接到单个列的sum
组来解决多个步骤中的问题,如下所示:
dt.out1 = dt[, sum(v1), by = grp]
dt.out2 = dt[, lapply(.SD,mean), by = grp, .SDcols = sd.cols]
dt.out = merge(dt.out1, dt.out2, by = "grp")
> dt.out
grp V1 v2 v3
1: a 6.091355 -0.0272192 0.008157602
2: b -2.782252 -0.1495292 0.199925178
3: c -1.070608 -0.1781543 -0.137625004
我确信这是一个我想念的相当简单的事情,提前感谢任何指导。
答案 0 :(得分:28)
更新:问题#495现已解决this recent commit,我们现在可以做到这一点:
require(data.table) # v1.9.7+
set.seed(1L)
dt = data.table(grp = sample(letters[1:3],100, replace = TRUE),
v1 = rnorm(100),
v2 = rnorm(100),
v3 = rnorm(100))
sd.cols = c("v2", "v3")
dt.out = dt[, list(v1 = sum(v1), lapply(.SD,mean)), by = grp, .SDcols = sd.cols]
但请注意,在这种情况下,v2
将作为列表返回。那是因为你有效地做list(val, list())
。你打算做的或许是:
dt[, c(list(v1=sum(v1)), lapply(.SD, mean)), by=grp, .SDcols = sd.cols]
# grp v1 v2 v3
# 1: a -6.440273 0.16993940 0.2173324
# 2: b 4.304350 -0.02553813 0.3381612
# 3: c 0.377974 -0.03828672 -0.2489067
查看旧答案的历史记录。
答案 1 :(得分:8)
试试这个:
dt[,list(sum(v1), mean(v2), mean(v3)), by=grp]
在data.table
中,在第二个参数中使用list()
可以描述导致最终data.table
的一组列。
对于它的价值,.SD
可能会很慢[^ 1],所以你可能想要避免它,除非你真的需要子集data.table
中提供的所有数据,就像你可能需要的那样更复杂的功能。
另一个选项,如果.SDcols
有很多列,那就是使用data.table
合并语法在一行中进行合并。
例如:
dt[, sum(v1), by=grp][dt[,lapply(.SD,mean), by=grp, .SDcols=sd.cols]]
要使用merge
中的data.table
,您需要先在setkey()
上使用data.table
,以便知道如何匹配。
所以,首先你需要:
setkey(dt, grp)
然后您可以使用上面的行来产生等效结果。
[^ 1]:我发现当你的团队数接近总行数时尤其如此。例如,这可能发生在您的密钥是个人ID并且许多人只有一两个观察值的情况下。