【问题标题】:Avoid using a loop to get sum of rows in R, where I want to start and stop the sum on different columns for each row避免使用循环来获取 R 中的行总和,我想在其中开始和停止每行不同列的总和
【发布时间】:2026-02-14 22:10:02
【问题描述】:

我对来自 Stata 的 R 比较陌生。我有一个包含 100 多列和数千行的数据框。每行都有一个起始值、终止值和 100 多列数值。目标是获取从起始值对应的列到终止值对应的列的每一行的总和。这足以直接在循环中执行,如下所示(data.frame 是 df,start 是开始列,stop 是停止列):

for(i in 1:nrow(df)) {
    df$out[i] <- rowSums(df[i,df$start[i]:df$stop[i]])
}

这很好用,但需要 15 分钟左右。有人对更快的方法有什么建议吗?

【问题讨论】:

    标签: r loops


    【解决方案1】:

    您可以使用一些代数来做到这一点(如果您有足够的内存量):

    DF <- data.frame(start=3:7, end=4:8)
    DF <- cbind(DF, matrix(1:50, nrow=5, ncol=10))
    
    #  start end 1  2  3  4  5  6  7  8  9 10
    #1     3   4 1  6 11 16 21 26 31 36 41 46
    #2     4   5 2  7 12 17 22 27 32 37 42 47
    #3     5   6 3  8 13 18 23 28 33 38 43 48
    #4     6   7 4  9 14 19 24 29 34 39 44 49
    #5     7   8 5 10 15 20 25 30 35 40 45 50
    
    take <- outer(seq_len(ncol(DF)-2)+2, DF$start-1, ">") &
            outer(seq_len(ncol(DF)-2)+2, DF$end+1, "<")
    
    diag(as.matrix(DF[,-(1:2)]) %*% take)
    #[1]  7 19 31 43 55
    

    【讨论】:

      【解决方案2】:

      如果您正在处理所有相同类型的值,您通常希望在矩阵中执行操作。这是一个矩阵形式的解决方案:

      rows <- 10^3
      cols <- 10^2
      start <- sample(1:cols, rows, replace=T)
      end <- pmin(cols, start + sample(1:(cols/2), rows, replace=T))
      
      # first 2 cols of matrix are start and end, the rest are
      # random data
      
      mx <- matrix(c(start, end, runif(rows * cols)), nrow=rows)
      
      # use `apply` to apply a function to each row, here the 
      # function sums each row excluding the first two values
      # from the value in the start column to the value in the
      # end column
      
      apply(mx, 1, function(x) sum(x[-(1:2)][x[[1]]:x[[2]]]))
      
      # df version
      
      df <- as.data.frame(mx)  
      df$out <- apply(df, 1, function(x) sum(x[-(1:2)][x[[1]]:x[[2]]]))
      

      您可以使用as.matrix 将您的data.frame 转换为矩阵。如图所示,您还可以直接在 data.frame 上运行应用程序,这仍然应该相当快。您的代码的真正问题是您正在修改数据框nrow 次,并且修改数据框非常慢。通过使用 apply,您可以通过生成答案($out 列)来解决这个问题,然后您可以将其 cbind 回您的数据框(这意味着您只需修改一次数据框)。

      【讨论】:

      • 很好,但请将问题标记为已回答(如果您真的喜欢,请点赞!)