data.table:表

时间:2016-03-23 10:19:18

标签: r group-by sum data.table

我有一个像这样的data.table out(实际上它要大得多):

out <-      code weights group
        1:    2   0.387      1
        2:    1   0.399      1
        3:    2   1.610      1
        4:    3   1.323      2
        5:    2   0.373      2                                            
        6:    1   0.212      2
        7:    3   0.316      3
        8:    2   0.569      3
        9:    1   0.120      3
       10:    1   0.354      3

它有3组不同的代码(第1列)。在组#1中,代码3不会出现,而在另一组中则显示。

然后,我想对每个组和代码组合的权重求和。我用这个命令实现了这个目的:

sum.dt <- out[,.(sum(weights)), by=list(code,group)][order(-V1)]

这种方法效果很好,但它没有组合1和代码3的组合,因为它不在out表中。我希望在sum.dt中包含所有可能的组合,如果源表中没有出现组合,则它应总计为0,这意味着列V1在此行中应为0。 / p>

知道如何实现这个目标吗?

2 个答案:

答案 0 :(得分:6)

使用CJ(交叉联接),您可以添加缺少的组合:

library(data.table)
setkey(out, code, group)
out[CJ(code, group, unique = TRUE)
    ][, lapply(.SD, sum), by = .(code, group)
      ][is.na(weights), weights := 0]

给出:

   code group weights
1:    1     1   0.399
2:    1     2   0.212
3:    1     3   0.474
4:    2     1   1.997
5:    2     2   0.373
6:    2     3   0.569
7:    3     1   0.000
8:    3     2   1.323
9:    3     3   0.316

或者xtabs正如@alexis_laz在评论中所示:

xtabs(weights ~ group + code, out)

给出:

     code
group     1     2     3
    1 0.399 1.997 0.000
    2 0.212 0.373 1.323
    3 0.474 0.569 0.316

如果要在长格式数据框中获取此输出,可以将xtabs代码包装在 reshape2 melt函数中(或 data.table )包:

library(reshape2)
res <- melt(xtabs(weights ~ group + code, out))

给出:

> class(res)
[1] "data.frame"
> res
  group code value
1     1    1 0.399
2     2    1 0.212
3     3    1 0.474
4     1    2 1.997
5     2    2 0.373
6     3    2 0.569
7     1    3 0.000
8     2    3 1.323
9     3    3 0.316

您也可以使用 dplyr tidyr 的组合来完成此操作:

library(dplyr)
library(tidyr)
out %>%
  complete(code, group, fill = list(weights=0)) %>%
  group_by(code, group) %>% 
  summarise(sum(weights))

答案 1 :(得分:1)

我遇到了类似的问题,并且CJ由于某种原因无法正常工作。我最终使用的一个相对简单的解决方案是先调用dcast,然后调用melt(类似于上面的xtable解决方案),这也可以方便地为缺失的组合指定填充值。

sum.dt <- dcast(out, code ~ group, value.var = 'weights', 
                fun.aggregate = sum, fill = 0)
sum.dt <- melt(sum.dt, id.vars = 'code', variable.name = 'group')

这给

> sum.dt
   code group value
1:    1     1 0.399
2:    2     1 1.997
3:    3     1 0.000
4:    1     2 0.212
5:    2     2 0.373
6:    3     2 1.322
7:    1     3 0.474
8:    2     3 0.569
9:    3     3 0.316