【问题标题】:R aggregate and handle missing combinationsR聚合并处理缺失的组合
【发布时间】:2015-08-27 16:49:58
【问题描述】:

我有一个数据框,其中包含我的数据 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 个 subjs * 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,但我认为它并不能完全回答我的问题。

【问题讨论】:

    标签: r


    【解决方案1】:

    您需要 (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 采用其参数的“交叉”或“笛卡尔”乘积。 (@nongkrong 的回答中看到的expand.grid 是基本的 R 类比。)X[Y, j, by=.EACHI] 语法表示:合并 XY,并且对于合并列的每个唯一组合,计算 j。在这种情况下,您正在寻找length,它与行数相同;在 data.table 中,.N 是这个数字的快捷方式。

    对于这种特殊情况,即简单地汇总以计算观察值,我认为@jeremycg 答案中的方法更有意义——使用专门为频率制表设计的函数。

    【讨论】:

      【解决方案2】:

      你可以从基地使用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]))
      

      【讨论】:

        【解决方案3】:

        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
        

        【讨论】:

          猜你喜欢
          • 2021-02-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-26
          • 2017-08-08
          相关资源
          最近更新 更多