【问题标题】:Sequential adding of n elementsn个元素的顺序添加
【发布时间】:2021-12-02 11:00:17
【问题描述】:

我在 R 中遇到了一个问题,我需要在 R 中操作向量。

假设我有一个长度为 12 的向量:

vector <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)

我现在需要将元素1+23+45+6 等添加到一个新向量中,在示例中为:

newvector <- c(3, 7, 11, 15, 19, 23) 

我需要对更长的序列执行相同的操作,例如添加前三个,然后是 4-6,然后是 7-9 等等。

newvector <- c(6, 15, 24, 33) 

等等。

【问题讨论】:

    标签: r vector sum sequence


    【解决方案1】:

    将向量放入矩阵中,然后使用colSums。这里有一个函数可以做到这一点。

    vector <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
    
    calculate_sum <- function(v, n) {
      colSums(matrix(v, nrow = n))
    }
    
    calculate_sum(vector, 2)
    #[1]  3  7 11 15 19 23
    
    calculate_sum(vector, 3)
    #[1]  6 15 24 33
    

    【讨论】:

      【解决方案2】:

      一个选项可能是:

      tapply(x, cumsum(seq_along(x) %% 2 == 1), sum)
      
       1  2  3  4  5  6 
       3  7 11 15 19 23 
      

      对于 n = 3:

      tapply(x, cumsum(seq_along(x) %% 3 == 1), sum)
      
       1  2  3  4 
       6 15 24 33
      

      【讨论】:

        【解决方案3】:

        我会这样做:split 将向量分成 n 个组,Reduce 将每个组的第 n 个元素相加。

        newvector <- Reduce(`+`, split(vector,c(1,2)))
        [1]  3  7 11 15 19 23
        

        作为一个函数,你可以这样:

        splitSum <- function(v, n) Reduce(`+`, split(v, c(1:n))) 
        splitSum(vector,3)
        [1]  6 15 24 33
        

        【讨论】:

          【解决方案4】:
          v <- 1:12
          
          v1 <- rep(0, ((length(v))/2))
          
          for(i in 1:((length(v))/2))
          v1[i] <- v[i]+v[i+1]
          
          v1
          

          我只是使用了for 循环。也许在使用 if 条件之前检查向量长度是否可以分成 2 个和 3 个元素的组可能会改善这一点...

          【讨论】:

            【解决方案5】:

            带有一些基准测试的RcppRoll 解决方案:

            library(RcppRoll)
            #> Warning: package 'RcppRoll' was built under R version 4.1.2
            
            v <- as.numeric(1:12e4)
            n <- 3L
            
            fRoll <- function(v, n) roll_sum(v, n, by = n)
            fMatrix <- function(v, n) colSums(matrix(v, nrow = n))
            fCumsum <- function(v, n) diff(c(0, cumsum(v))[seq(1, length(v) + 1L, n)])
            fReduce <- function(v, n) Reduce(`+`, split(v, 1:n))
            fLoop <- function(v, n) {
              vOut <- numeric(ceiling(length(v)/n))
              idx <- 0:(n - 1)
              
              for (i in seq_along(vOut)) {
                vOut[i] <- sum(v[i*n - idx])
              }
              
              return(vOut)
            }
            fApply1 <- function(v, n) tapply(v, cumsum(seq_along(v) %% n == 1), sum)
            fApply2 <- function(v, n) tapply(v, 0:(length(v) - 1) %/% n, sum)
            
            microbenchmark::microbenchmark(fRoll(v, n), fMatrix(v, n), fCumsum(v, n), fReduce(v, n), fLoop(v, n), fApply1(v, n), fApply2(v, n))
            #> Unit: microseconds
            #>           expr     min       lq      mean   median       uq      max neval
            #>    fRoll(v, n)   145.7   215.45   290.512   234.35   284.05   1559.6   100
            #>  fMatrix(v, n)   282.0   360.85   428.385   382.20   437.70   1678.0   100
            #>  fCumsum(v, n)  1724.5  1805.05  2060.008  1859.15  2094.30   6169.5   100
            #>  fReduce(v, n)  1852.5  1943.15  2056.358  1985.75  2096.15   4335.6   100
            #>    fLoop(v, n) 19976.5 22618.05 25725.492 23860.95 25300.10  73618.3   100
            #>  fApply1(v, n) 69336.2 73841.35 77741.583 76639.80 80791.70 123253.8   100
            #>  fApply2(v, n) 69178.3 73870.80 77691.152 76582.65 79066.60 101159.1   100
            
            # check that all the functions return the same result
            results <- lapply(list(fRoll, fMatrix, fCumsum, fReduce, fLoop, fApply1, fApply2), function(f) as.numeric(f(v, n)))
            sum(duplicated.default(results)) == length(results) - 1L
            #> [1] TRUE
            
            Created on 2021-12-02 by the reprex package (v2.0.1)
            

            可能不会在 base r 中击败 colSums(matrix(

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2021-07-10
              • 1970-01-01
              • 2023-04-05
              • 2016-04-30
              • 2018-08-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多