【问题标题】:Calculate row-average for columns based on condition met by other columns根据其他列满足的条件计算列的行平均值
【发布时间】:2018-02-13 07:12:52
【问题描述】:

我想根据其他列中的值对某些列进行行平均。如果我们采用以下数据集:

library(data.table)
test <- data.table(s1=c(0,4,29,9,1,2,10),
                   s2=c(20,17,11,15,32,15,10),
                   s3=c(1,0,2,1,4,7,0),
                   m1=c(0,4,29,NA,1,22,8),
                   m2=c(20,17,NA,15,32,15,12),
                   m3=c(1,0,1,1,1,NA,0),
                   z=c(1,5,25,5,30,20,10)
)

我想取s1, s2, s3 的平均值并根据m1, m2, m3z 的值创建一个新列;具体使用以下条件。

ifelse( !is.na(m) & m<z, s, NA)

也就是说,如果m 不是NAm &lt; z,那么只有s 才应该考虑行平均。

到目前为止,我已经完成了这项工作,但似乎太冗长了

test[,t1:=ifelse(!is.na(m1) & m1<z,s1,NA),]
test[,t2:=ifelse(!is.na(m2) & m2<z,s2,NA),]
test[,t3:=ifelse(!is.na(m3) & m3<z,s3,NA),]

test[,s_avg:=rowMeans(.SD,na.rm = TRUE),.SDcols=c('t1','t2','t3')]

我们也将赞赏另一种 data.frame 解决方案。

编辑: t 列是不需要的。

【问题讨论】:

    标签: r data.table mean


    【解决方案1】:

    一种选择是使用Map 对“s”和“m”的对应列进行比较

    nm1 <- grep("s\\d+", names(test), value = TRUE)
    nm2 <- grep("m\\d+", names(test), value = TRUE)
    test[, paste0("t", 1:3) := Map(function(x, y) 
             ifelse(y < z & !is.na(y), x, NA), .SD[, ..nm1], .SD[, ..nm2]) ]
    

    然后执行 OP 帖子中的最后一步。目前尚不清楚 OP 是否需要“t”列。

    test[,s_avg:=rowMeans(.SD,na.rm = TRUE),.SDcols=c('t1','t2','t3')]
    test
    #    s1 s2 s3 m1 m2 m3  z t1 t2 t3 s_avg
    #1:  0 20  1  0 20  1  1  0 NA NA   0.0
    #2:  4 17  0  4 17  0  5  4 NA  0   2.0
    #3: 29 11  2 29 NA  1 25 NA NA  2   2.0
    #4:  9 15  1 NA 15  1  5 NA NA  1   1.0
    #5:  1 32  4  1 32  1 30  1 NA  4   2.5
    #6:  2 15  7 22 15 NA 20 NA 15 NA  15.0
    #7: 10 10  0  8 12  0 10 10 NA  0   5.0
    

    如果我们不需要't'列,那么可以在上面的步骤中创建s_avg

    test[,  s_avg := rowMeans(mapply(function(x, y) x *(NA^!(y < z & !is.na(y))),
                         .SD[, ..nm1], .SD[, ..nm2]), na.rm = TRUE) ]
    test
    #   s1 s2 s3 m1 m2 m3  z s_avg
    #1:  0 20  1  0 20  1  1   0.0
    #2:  4 17  0  4 17  0  5   2.0
    #3: 29 11  2 29 NA  1 25   2.0
    #4:  9 15  1 NA 15  1  5   1.0
    #5:  1 32  4  1 32  1 30   2.5
    #6:  2 15  7 22 15 NA 20  15.0
    #7: 10 10  0  8 12  0 10   5.0
    

    即使grep这一步也可以在上面的代码行中完成。


    另一种选择是在创建行索引后将melt它转换为'long'格式,然后对索引进行连接以创建's_avg'

    test[, ind := seq_len(.N)]
    test[melt(test, measure = patterns("^s\\d+", "^m\\d+"),
         value.name = c("s", "m"))[!is.na(m) & m < z][, 
         .(s_avg = mean(s, na.rm = TRUE)), ind], 
                 on = .(ind)][order(ind)][, ind := NULL][]
    #    s1 s2 s3 m1 m2 m3  z s_avg
    #1:  0 20  1  0 20  1  1   0.0
    #2:  4 17  0  4 17  0  5   2.0
    #3: 29 11  2 29 NA  1 25   2.0
    #4:  9 15  1 NA 15  1  5   1.0
    #5:  1 32  4  1 32  1 30   2.5
    #6:  2 15  7 22 15 NA 20  15.0
    #7: 10 10  0  8 12  0 10   5.0
    

    【讨论】:

      【解决方案2】:

      看来你不需要ifelse。只需使用i 表达式即可。

      iter <- 1:3
      t <- paste0("t", iter)
      s <- paste0("s", iter)
      m <- paste0("m", iter)
      for (i in iter) test[!is.na(get(m[i])) & get(m[i]) < z, (t[i]) := get(s[i])]
      test[, s_avg := rowMeans(.SD, na.rm = TRUE), .SDcols = t]
      print(test)
      #>    s1 s2 s3 m1 m2 m3  z t1 t2 t3 s_avg
      #> 1:  0 20  1  0 20  1  1  0 NA NA   0.0
      #> 2:  4 17  0  4 17  0  5  4 NA  0   2.0
      #> 3: 29 11  2 29 NA  1 25 NA NA  2   2.0
      #> 4:  9 15  1 NA 15  1  5 NA NA  1   1.0
      #> 5:  1 32  4  1 32  1 30  1 NA  4   2.5
      #> 6:  2 15  7 22 15 NA 20 NA 15 NA  15.0
      #> 7: 10 10  0  8 12  0 10 10 NA  0   5.0
      

      【讨论】:

        【解决方案3】:

        方法一:

        test[ , avg := rowMeans( test[, .(ifelse( m1 < z, s1, NA),
                                          ifelse( m2 < z, s2, NA),
                                          ifelse( m3 < z, s3, NA)) ],
                                 na.rm = TRUE ) ]
        

        方法2:使用表达式

        expr <- paste0("ifelse( m", 1:3, " < z, s", 1:3, ", NA )")
        test[ , avg := rowMeans( test[, lapply( expr, function(x) eval(parse(text = x)))],
                                 na.rm = TRUE ) ]
        

        输出:

        test
        #    Time Zone quadrat s1 s2 s3 m1 m2 m3  z  avg
        # 1:    0    1       1  0 20  1  0 20  1  1  0.0
        # 2:    0    1       2  4 17  0  4 17  0  5  2.0
        # 3:    0    0       3 29 11  2 29 NA  1 25  2.0
        # 4:    7    1       1  9 15  1 NA 15  1  5  1.0
        # 5:    7    0       2  1 32  4  1 32  1 30  2.5
        # 6:    7    0       3  2 15  7 22 15 NA 20 15.0
        # 7:   12    1       1 10 10  0  8 12  0 10  5.0
        

        【讨论】:

          猜你喜欢
          • 2022-11-15
          • 2014-11-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-11-03
          • 2021-04-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多