【问题标题】:avoiding nested sapply when collapsing variable in data.frame with multiple factors使用多个因素折叠 data.frame 中的变量时避免嵌套 sapply
【发布时间】:2019-12-20 09:32:18
【问题描述】:

我有一个包含多个因子和多个数字变量的数据框。我想瓦解其中一个因素(比如说平均)。

在我的尝试中,我只能想到嵌套 sapply 或 for 循环来隔离要平均的数字元素。

var <- data.frame(A = c(rep('a',8),rep('b',8)), B = 
c(rep(c(rep('c',2),rep('d',2)),4)), C = c(rep(c('e','f'),8)),
                  D = rnorm(16), E = rnorm(16))
> var
   A B C           D           E
1  a c e  1.1601720731 -0.57092435
2  a c f -0.0120178626  1.05003748
3  a d e  0.5311032778  1.67867806
4  a d f -0.3399901000  0.01459940
5  a c e -0.2887561691 -0.03847519
6  a c f  0.0004299922 -0.36695879
7  a d e  0.8124655890  0.05444033
8  a d f -0.3777058654  1.34074427
9  b c e  0.7380720821  0.37708543
10 b c f -0.3163496271  0.10921373
11 b d e -0.5543252191  0.35020193
12 b d f -0.5753686426  0.54642790
13 b c e -1.9973216646  0.63597405
14 b c f -0.3728926714 -3.07669300
15 b d e -0.6461596329 -0.61659041
16 b d f -1.7902722068 -1.06761729


sapply(4:ncol(var), function(i){
  sapply(1:length(levels(var$A)), function(j){
    sapply(1:length(levels(var$B)), function(t){
      sapply(1:length(levels(var$C)), function(z){
        mean(var[var$A == levels(var$A)[j] & 
var$B == levels(var$B)[t] & 
var$C == levels(var$C)[z],i])
      })
    })
  })
})

             [,1]       [,2]
[1,]  0.435707952 -0.3046998
[2,] -0.005793935  0.3415393
[3,]  0.671784433  0.8665592
[4,] -0.358847983  0.6776718
[5,] -0.629624791  0.5065297
[6,] -0.344621149 -1.4837396
[7,] -0.600242426 -0.1331942
[8,] -1.182820425 -0.2605947

没有这么多的sapply,有没有办法做到这一点?也许与 mapply 或外部

【问题讨论】:

    标签: r for-loop sapply


    【解决方案1】:

    也许只是,

    var <- data.frame(A = c(rep('a',8),rep('b',8)), B = 
                        c(rep(c(rep('c',2),rep('d',2)),4)), C = c(rep(c('e','f'),8)),
                      D = rnorm(16), E = rnorm(16))
    
    library(dplyr)
    var %>%
      group_by(A,B,C) %>%
      summarise_if(is.numeric,mean)
    

    (请注意,您显示的输出不是我在运行您的 sapply 代码时得到的,但上面的输出与我在运行您的 sapply 时得到的相同。)

    【讨论】:

    • 对不起,那是因为我在没有控制种子的情况下运行了两次。你的代码优雅地完成了这个技巧。谢谢
    【解决方案2】:

    对于内联聚合(保持相同的数据帧行数),考虑ave

    var$D_mean <- with(var, ave(D, A, B, C, FUN=mean))
    var$E_mean <- with(var, ave(E, A, B, C, FUN=mean))
    

    对于完全聚合(折叠到因子组),请考虑aggregate

    aggregate(. ~ A + B + C, var, mean)
    

    【讨论】:

    • 我觉得你需要aggregate(cbind(D, E) ~ ., FUN = mean, data = var)
    • 正确!没有看到第二个数字。
    • 只是跟进,因为我也喜欢这个解决方案。如果我有 100 列,我必须把 cbind 放在一起吗?有没有办法在没有cbind 参考的情况下考虑所有这些?
    • 非常感谢@IceCreamToucan 和@Parfait!当输出不是单个数字而是向量时,aggregate 实际上使用起来要简单得多,比如向量的 z-score。
    【解决方案3】:

    我将使用 data.table 解决方案完成三位一体。这里.SDby 部分中未列出的所有列的data.table。这几乎是 this question 的骗局(唯一的区别是 >1 列被汇总),所以如果您想要更多解决方案,请单击它。

    library(data.table)
    setDT(var)
    
    var[, lapply(.SD, mean), by = .(A, B, C)]
    #    A B C           D            E
    # 1: a c e  0.07465822  0.032976115
    # 2: a c f  0.40789460 -0.944631574
    # 3: a d e  0.72054938  0.039781185
    # 4: a d f -0.12463910  0.003363382
    # 5: b c e -1.64343115  0.806838905
    # 6: b c f -1.08122890 -0.707975411
    # 7: b d e  0.03937829  0.048136471
    # 8: b d f -0.43447899  0.028266455
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-31
      • 1970-01-01
      • 2020-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多