R聚合和处理缺失组合

3

我有一个数据框包含数据x,以及三个不同的因素(受试者、任务和正确答案)。

 subj <- rep(c(1,2,3), times=4)
 task <- c("A","A","A","A","A","A","B","B","B","B","B","B")
 correct <- c(1,1,1,0,0,0,1,1,1,0,0,0)
 x <- runif(12)
 df <- data.frame(subj, task, correct, x)

我希望能够得到这三个因素每种可能组合下的试验次数(3个被试 * 2个任务 * 2个正确/错误 = 12种组合)。当然,这只是一个不好的例子,因为我只有每个组合的一个试验,但您可以想象一下。所以我的操作如下:

 > aggregate(x~subj+task+correct, length, data=df)
    subj task correct x
 1     1    A       0 1
 2     2    A       0 1
 3     3    A       0 1
 4     1    B       0 1
 5     2    B       0 1
 6     3    B       0 1
 7     1    A       1 1
 8     2    A       1 1
 9     3    A       1 1
 10    1    B       1 1
 11    2    B       1 1
 12    3    B       1 1

现在假设我的数据中有一些缺失的组合:

 > newdf <- df[-2,]

使用相同的聚合函数将不会显示所有可能的组合,只有12个中的11个。我希望对于我缺失的组合能够获得长度为0(或NA或类似的结果)。
注意:这里有一个类似的问题链接,但我认为它并没有解决我的问题。
3个回答

7

您需要执行以下操作来进行聚合:

  1. 获取分组列的笛卡尔积
  2. 将其与数据框合并
  3. 执行聚合操作

在data.table中,代码如下:

library(data.table) # version 1.9.5+

setDT(newdf, key = c("subj","task","correct"))
newdf[CJ(subj, task, correct, unique=TRUE), .N, by=.EACHI]

这提供了

    subj task correct N
 1:    1    A       0 1
 2:    1    A       1 1
 3:    1    B       0 1
 4:    1    B       1 1
 5:    2    A       0 1
 6:    2    A       1 0 # not NA
 7:    2    B       0 1
 8:    2    B       1 1
 9:    3    A       0 1
10:    3    A       1 1
11:    3    B       0 1
12:    3    B       1 1

setDT会修改newdf,使得它能够使用data.table语法。设置key会按照这些列排序并准备好进行更快的合并。

CJ对其参数执行"Cross"或"Cartesian"乘积操作。(在@nongkrong的答案中看到的expand.grid是基本的R模拟方法。)语法X[Y,j,by=.EACHI]表示:合并XY,对于每个唯一的合并列组合,计算j。在这种情况下,您正在寻找length,它与行数相同;在data.table中,.N是该数字的快捷方式。

对于这种特殊情况,仅聚合以计算观测次数,我认为@jeremycg答案中的方法更有意义——使用专门用于频率制表的函数。


6
您可以使用基本的xtabs功能:
as.data.frame(xtabs(~ subj + task + correct, data = newdf))

   subj task correct Freq
1     1    A       0    1
2     2    A       0    1
3     3    A       0    1
4     1    B       0    1
5     2    B       0    1
6     3    B       0    1
7     1    A       1    1
8     2    A       1    0
9     3    A       1    1
10    1    B       1    1
11    2    B       1    1
12    3    B       1    1

再次来自 @Frank,更加简单:

as.data.frame(table(newdf[1:3]))


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接