R聚合并处理缺失的组合

时间:2015-08-27 16:49:59

标签: r

我有一个数据框,包含我的数据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,或类似的东西),用于我缺少的组合。

注意:有一个类似的问题here,但我认为它并没有完全回答我的问题。

3 个答案:

答案 0 :(得分:7)

您需要(1)获取分组列的笛卡尔积,(2)将其与data.frame合并,以及(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采用其论点的“十字架”或“笛卡尔”产品。 (expand.grid,在@ nongkrong的答案中看到,是基本的R模拟。)语法X[Y, j, by=.EACHI]说:merge XY,以及每个独特的合并列组合,计算j。在这种情况下,您正在寻找length,这与行数相同;在data.table中,.N是此数字的快捷方式。

对于这个特殊情况,简单地聚合计数观察,我认为@ jeremycg的答案中的方法更有意义 - 使用专为频率制表设计的功能。

答案 1 :(得分: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]))

答案 2 :(得分:2)

sqldf package的一个小技巧:

library(sqldf)
newdf <- df[-2,]
combinations <- sqldf('select * 
                       from (select distinct subj from newdf) as a, 
                            (select distinct task from newdf) as b, 
                            (select distinct correct from newdf) as c')
sqldf('select c.*, count(d.x) as count_x 
       from combinations as c 
           left join newdf as d on c.subj=d.subj 
                          and c.task=d.task 
                          and c.correct=d.correct 
       group by c.subj, c.task, c.correct')
##    subj task correct count_x
## 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
## 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

sqldf包允许您使用SQL查询操作数据框,就像它们是数据库表一样。

<强>加成

如果您想使用此数据创建“数据透视表”,并使用正确的(1)和错误的(1)作为数据标签,则可以使用reshape包:

aggregate_df <- sqldf('select c.*, count(d.x) as count_x 
                       from combinations as c 
                           left join newdf as d on c.subj=d.subj 
                                               and c.task=d.task 
                                               and c.correct=d.correct 
                       group by c.subj, c.task, c.correct')
library(reshape)
md <- melt(aggregate_df, id=c('subj','task','correct'))
cast(md, subj+task~correct)
##   subj task 0 1
## 1    1    A 1 1
## 2    1    B 1 1
## 3    2    A 1 0
## 4    2    B 1 1
## 5    3    A 1 1
## 6    3    B 1 1