R - 像函数一样确保所有因子水平的相互作用

时间:2016-03-29 15:37:48

标签: r aggregate-functions

我想知道如何确保在使用聚合时我包含所有因素的相互作用,即使它们不会出现在给定的数据集中。

dff <- data.frame(a=as.factor(c(rep(1,3), rep(2,4), rep(3,3))),
                  b=as.factor(c(rep("A", 4), rep("B",6))),
                  c=sample(100,10))

levels(dff$b) <- c(levels(dff$b), "C")
levels(dff$a) <- c(levels(dff$a), 10)

dff$b
#[1] A A A A B B B B B B
#Levels: A B C
dff$a
#[1] 1 1 1 2 2 2 2 3 3 3
#Levels: 1 2 3 10

aggregate(c~a+b, dff, sum)
#  a b   c
#1 1 A 233
#2 2 A  78
#3 2 B 212
#4 3 B  73

我想要的是

      a b   c
    1 1 A 233
    2 1 B   0
    3 1 C   0
    4 2 A  78
    5 2 B 212
    6 2 C   0
    7 3 A   0
    8 3 B  73
    9 3 C   0
   10 10 A  0
   11 10 B  0
   12 10 C  0  

NA也很好。

我想要这种格式的原因是因为我需要将dff $ c与来自其他数据集的结果进行交互,如果不考虑所有因子水平,它们可能具有不同的长度。我尝试避免合并,而是使用矢量计算。

提前谢谢你。

1 个答案:

答案 0 :(得分:2)

如果您的聚合函数只是sum,您可以使用xtabs,这将创建一个包含类table的对象。因此,您可以使用data.frame,它会调用相应的“方法”,从而创建“长”data.frame

data.frame(xtabs(c ~ b + a, dff))
#    b  a Freq
# 1  A  1  121
# 2  B  1    0
# 3  C  1    0
# 4  A  2   89
# 5  B  2  203
# 6  C  2    0
# 7  A  3    0
# 8  B  3  126
# 9  C  3    0
# 10 A 10    0
# 11 B 10    0
# 12 C 10    0

这类似于@ nicola建议使用as.data.frame.table,它明确地将该方法调用为非明确属于类“table”但可被视为一个的东西。

此方法(以及随后的所有其他方法)的一个优点是您可以使用sum以外的其他功能。

as.data.frame.table(tapply(dff$c, dff[c("a","b")], sum))

如果merge没问题,您可以继续执行aggregate步骤。在这种情况下,我们会在您的因子向量expand.grid上使用levels

merge(expand.grid(lapply(dff[c(1, 2)], levels)), 
      aggregate(c~a+b, dff, sum, drop = FALSE), all = TRUE)

可以在“data.table”中采用类似的方法:

library(data.table)
as.data.table(dff)[, sum(c), by = .(a, b)][do.call(CJ, lapply(dff[c(1, 2)], levels)), on = c("a", "b")]

或使用“dplyr”+“tidyr”(基本上隐藏了合并,但最终使用left_join来创建缺少的组合):

library(dplyr)
library(tidyr)

dff %>%
  group_by(a, b) %>%
  summarise(c = sum(c)) %>%
  complete(a, b, fill = list(c = 0))