在 df 上做条件求和比 for 循环更好的方法?

Better way to do conditional-sum on df than for-loop?

我正在使用 for 循环对数据帧求和。我知道在 R 中循环通常不是一个好主意,使用 sapply 或 aggregate 是更好的方法,但我只是不知道如何在我的案例中使用它。

我想以迭代的方式根据两列的条件对一列求和。

以下是我想以更好的方式让您理解的内容:

sample  <- data.frame( ID = c("bli","bla","blou","qhq","bidi","bada","bodo"),
        A = c(1,0,1,1,0,1,1) , 
        B = c(0,1,1,0,0,1,0) ,
        C = c(0,1,1,0,0,1,1) 

                  )


 g  <-  NULL 
bli  <- 1:length(sample)
for (j in 2:length(sample)) {
  a <- sum(subset(sample,sample[,c(j) ] ==1 , c(j)))
  for (i in 2:length(sample)) 
    if (bli[j] != bli[i]) {
    b  <- sum(subset(sample,sample[,c(j)] ==1 & sample[,c(i) ] ==1 , c(i)))
    c <- names(sample[j])
    d <- names(sample[i])
    e  <- cbind(c,d,a,b)
    f  <- data.frame(e)
    g <-  rbind(g,f) } 
  else {
    NULL
}

  }
g

谢谢

您可以尝试 expand.grid(@thelatemail 建议)。以下代码的摘要是:

  1. 创建一个 "index" 的列名(即 "nm1"),我们需要所有的组合
  2. 自己尝试 expand.grid 或 "nm1" (expand.grid(nm1, nm1))。语法 list(nm1) 有点笼统,因此您可以通过在 rep.
  3. 中指定 times 来创建多路组合
  4. 删除相同的行("indx1")
  5. 使用 sapply 遍历 "indx1" 的行并根据循环中的行索引对 "sample" 数据集进行子集化。
  6. 根据"indx1"第一列的子集做sum,根据子集数据集的元素是否都为“1”sumsum 21=])
  7. cbind "indx1" 与 sapply 的转置 (t) 并重命名输出数据集的列。

    nm1 <- names(sample)[-1]
    indx <- expand.grid(rep(list(nm1),2),stringsAsFactors=FALSE)
    indx <- indx[,2:1]
    indx1 <- indx[indx[,1]!=indx[,2],]
    row.names(indx1) <- NULL
    res <-  cbind(indx1,t(sapply(seq_len(nrow(indx1)), function(i) {
                      x1 <-  unlist(indx1[i,])
                      x2 <- sample[,x1]
                   c(sum(x2[,1]), sum(x2[,1]&x2[,2])) }))
     )
    names(res) <- names(g)
    res
    #   c d a b
    #1 A B 5 2
    #2 A C 5 3
    #3 B A 3 2
    #4 B C 3 3
    #5 C A 4 3
    #6 C B 4 3
    

或者甚至不使用 sapply(会更快),在两个子集数据集 "i1"、"i2" 上使用 colSums

 i1 <- sample[indx1[,1]]
 i2 <- sample[indx1[,2]]
 a <- colSums(i1)
 b <- colSums(i1 &i2)
 #in case you have more than two columns
 #b <- colSums(Reduce(`&`,list(i1, i2)))
 res1 <- cbind(setNames(indx1, c('c', 'd')), a, b)