【问题标题】:Sum every nth points每n个点求和
【发布时间】:2013-02-22 07:35:19
【问题描述】:

我有一个向量,我需要对每个 n 数字求和并返回结果。这是我目前计划做的方式。有更好的方法吗?

v = 1:100
n = 10
sidx = seq.int(from=1, to=length(v), by=n)
eidx = c((sidx-1)[2:length(sidx)], length(v))
thesum = sapply(1:length(sidx), function(i) sum(v[sidx[i]:eidx[i]]))

这给出了:

thesum
 [1]  55 155 255 355 455 555 655 755 855 955

【问题讨论】:

    标签: r sum apply


    【解决方案1】:
    unname(tapply(v, (seq_along(v)-1) %/% n, sum))
    # [1] 55 155 255 355 455 555 655 755 855 955 
    

    【讨论】:

      【解决方案2】:

      更新:

      如果您想对每 n 个连续数字求和,请使用 colSums
      如果您想对每一个个数求和,请使用rowSums

      根据 Josh 的评论,这只有在 n 很好地分割 length(v) 时才有效。

      rowSums(matrix(v, nrow=n))
       [1] 460 470 480 490 500 510 520 530 540 550
      
      colSums(matrix(v, nrow=n))
       [1]  55 155 255 355 455 555 655 755 855 955
      

      【讨论】:

      • 仅当length(v) 可以被n 整除时才有效。否则矢量回收会咬你。 (参见例如v <- 1:3; n <- 2; matrix(v, nrow=n)。)
      • 只有在matrix(..., byrow=TRUE) 时才有效,因此@Andrie 回答他使用colSums 而不是rowSums。
      • @plannapus,不清楚 OP 是否想要每个 n 连续或每 n 个数字。
      • 如果是每个nth 号码,我会说只有550 是答案。 10th, 20th 等等.. 不是 1, 11..., 2, 12... 等等..
      • @Arun,你从哪里开始数 n 个数字?
      【解决方案3】:

      更新

      旧版本不工作。这是一个使用rep 创建分组因子的新遮阳篷。不用cut:

      n <- 5 
      vv <- sample(1:1000,100)
      seqs <- seq_along(vv)
      tapply(vv,rep(seqs,each=n)[seqs],FUN=sum)
      

      你可以使用tapply

      tapply(1:100,cut(1:100,10),FUN=sum)
      

      或获取列表

      by(1:100,cut(1:100,10),FUN=sum)
      

      编辑

      如果你有1:92,你可以用这个替换你的剪辑:

      cut(1:92,seq(1,92,10),include.lowest=T)
      

      【讨论】:

      • 我明白你为什么喜欢这个答案,但这不适用于你想对每 n 个元素求和的随机数字向量,不是吗?
      • @MaxM 你是对的。我会更新我的答案以包含一个新版本。
      【解决方案4】:

      一种方法是将向量转换为矩阵,然后取列总和:

      colSums(matrix(v, nrow=n))
      [1]  55 155 255 355 455 555 655 755 855 955
      

      请注意:这隐含地假设您的输入向量实际上可以重塑为矩阵。如果不能,R 将回收向量的元素以完成矩阵。

      【讨论】:

        【解决方案5】:
        v <- 1:100
        
        n <- 10
        
        cutpoints <- seq( 1 , length( v ) , by = n )
        
        categories <- findInterval( 1:length( v ) , cutpoints )
        
        tapply( v , categories , sum )
        

        【讨论】:

        • (+1) 这也给出了正确的结果,即使 v = 1:92 和 n = 10。
        【解决方案6】:

        我将添加另一种方法,无需 apply 家庭的任何功能

        v <- 1:100
        n <- 10
        
        diff(c(0, cumsum(v)[slice.index(v, 1)%%n == 0]))
        ##  [1]  55 155 255 355 455 555 655 755 855 955
        

        【讨论】:

        • 请注意,例如v &lt;- 1:99,这不包括最后 9 个数字的总和(可能会也可能不会)。
        • nv = length(v); i = c(seq_len(nv %/% n) * n, if (nv %% n) nv else NULL) 然后diff(c(0, cumsum(v)[i])) 似乎得到了length(v) == 0 和length(v) %% n != 0 的边缘情况。
        • slice.index(v, 1) 可以只替换为 v,如果我没记错的话。
        【解决方案7】:

        以下是目前提供的一些主要变体

        f0 <- function(v, n) {
            sidx = seq.int(from=1, to=length(v), by=n)
            eidx = c((sidx-1)[2:length(sidx)], length(v))
            sapply(1:length(sidx), function(i) sum(v[sidx[i]:eidx[i]]))
        }
        
        f1 <- function(v, n, na.rm=TRUE) {    # 'tapply'
            unname(tapply(v, (seq_along(v)-1) %/% n, sum, na.rm=na.rm))
        }
        
        f2 <- function(v, n, na.rm=TRUE) {    # 'matrix'
            nv <- length(v)
            if (nv %% n)
                v[ceiling(nv / n) * n] <- NA
            colSums(matrix(v, n), na.rm=na.rm)
        }
        
        f3 <- function(v, n) {                # 'cumsum'
            nv = length(v)
            i <- c(seq_len(nv %/% n) * n, if (nv %% n) nv else NULL)
            diff(c(0L, cumsum(v)[i]))
        }
        

        基本的测试用例可能是

        v = list(1:4, 1:5, c(NA, 2:4), integer())
        n = 2
        

        f0 在最终测试中失败,但这可能会被修复

        > f0(integer(), n)
        Error in sidx[i]:eidx[i] : NA/NaN argument
        

        cumsum 方法f3 存在舍入误差,并且在v 'poisons' 后期结果中早期存在 NA

        > f3(c(NA, 2:4), n)
        [1] NA NA
        

        在性能方面,原方案还不错

        > library(rbenchmark)
        > cols <- c("test", "elapsed", "relative")
        > v <- 1:100; n <- 10
        > benchmark(f0(v, n), f1(v, n), f2(v, n), f3(v, n),
        +           columns=cols)
              test elapsed relative
        1 f0(v, n)   0.012     3.00
        2 f1(v, n)   0.065    16.25
        3 f2(v, n)   0.004     1.00
        4 f3(v, n)   0.004     1.00
        

        但矩阵解决方案f2 似乎既快速又灵活(例如,调整对少于n 元素的尾随块的处理)

        > v <- runif(1e6); n <- 10
        > benchmark(f0(v, n), f2(v, n), f3(v, n), columns=cols, replications=10)
              test elapsed relative
        1 f0(v, n)   5.804   34.141
        2 f2(v, n)   0.170    1.000
        3 f3(v, n)   0.251    1.476
        

        【讨论】:

          【解决方案8】:

          一种方法是从zoo 使用rollapply:

          rollapply(v, width=n, FUN=sum, by=n)
          # [1]  55 155 255 355 455 555 655 755 855 955
          

          如果length(v)不是n的倍数:

          v <- 1:92
          
          rollapply(v, width=n, FUN=sum, by=n, partial=T, align="left")
          # [1]  55 155 255 355 455 555 655 755 855 183
          

          【讨论】:

            【解决方案9】:

            聚会有点晚了,但我还没有看到rowsum() 的答案。 rowsum() 被证明比 tapply() 更有效,而且我认为相对于其他一些响应,它也非常有效。

            rowsum(v, rep(seq_len(length(v)/n), each=n))[,1]
            #  1   2   3   4   5   6   7   8   9  10 
            # 55 155 255 355 455 555 655 755 855 955
            

            使用@Josh O'Brien 的分组技术可能会进一步提高效率。

            rowsum(v, (seq_along(v)-1) %/% n)[,1]
            #  0   1   2   3   4   5   6   7   8   9 
            # 55 155 255 355 455 555 655 755 855 955 
            

            只需包含unname() 即可删除组名。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2020-04-03
              • 1970-01-01
              • 2017-02-18
              • 2013-09-18
              • 2015-10-19
              • 1970-01-01
              • 2023-03-15
              • 2019-04-10
              相关资源
              最近更新 更多