使用data.table包,是否可以汇总保留输入中未出现的变量的数据组合?

使用plyr包,我知道如何使用.drop参数执行此操作,例如:

require(plyr)
df <- data.frame(categories = c(rep("A",3), rep("B",3), rep("C",3)), groups = c(rep(c("X", "Y"),4), "Z"), values = rep(1, 9))

df1 <- ddply(df, c("categories","groups"), .drop = F, summarise, sum = sum(values))


输出:

 categories groups sum
1          A      X   2
2          A      Y   1
3          A      Z   0
4          B      X   1
5          B      Y   2
6          B      Z   0
7          C      X   1
8          C      Y   1
9          C      Z   1


在这种情况下,即使总和为0,我也会保留所有组/类别组合。

最佳答案

好问题。这有两种方法。他们都使用逐个。

DT = as.data.table(df)
setkey(DT,categories,groups)
DT[CJ(unique(categories),unique(groups)), sum(values,na.rm=TRUE)]

   categories groups V1
1:          A      X  2
2:          A      Y  1
3:          A      Z  0
4:          B      X  1
5:          B      Y  2
6:          B      Z  0
7:          C      X  1
8:          C      Y  1
9:          C      Z  1


其中CJ代表交叉连接,请参见?CJ。 “逐个逐个”仅表示ji的每一行加入的每个组上执行。

诚然,乍一看似乎很棘手。这个想法是,如果您有一个已知的组子集,则此语法比对所有内容进行分组然后从所需的结果中仅选择结果要快。但是在这种情况下,无论如何您还是想要所有东西,所以除了可以查找数据中不存在的组(使用by无法做到)以外,没有太多优势。

另一种方法是先像往常一样by,然后将CJ()结果加入其中:

DT[,sum(values),keyby='categories,groups'][CJ(unique(categories),unique(groups))]
   categories groups V1
1:          A      X  2
2:          A      Y  1
3:          A      Z NA
4:          B      X  1
5:          B      Y  2
6:          B      Z NA
7:          C      X  1
8:          C      Y  1
9:          C      Z  1


但是您会得到NA而不是所需的0。可以根据需要使用set()替换它们。第二种方法可能会更快,因为两个unique调用的输入要小得多。

如果您经常这样做,那么这两种方法都可以包装成小的辅助函数。

08-19 23:41