每第n个点求和

时间:2013-03-07 07:33:26

标签: r sum apply

我有一个向量,我需要对每个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

9 个答案:

答案 0 :(得分:28)

unname(tapply(v, (seq_along(v)-1) %/% n, sum))
# [1] 55 155 255 355 455 555 655 755 855 955 

答案 1 :(得分:16)

更新

如果您想要每n个连续数字,请使用colSums
如果您要将每第n个数相加,请使用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

答案 2 :(得分:12)

更新

olde版本不起作用。这里是一个使用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)

答案 3 :(得分:7)

一种方法是将矢量转换为matric,然后取列总和:

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

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

答案 4 :(得分:4)

v <- 1:100

n <- 10

cutpoints <- seq( 1 , length( v ) , by = n )

categories <- findInterval( 1:length( v ) , cutpoints )

tapply( v , categories , sum )

答案 5 :(得分:3)

我将在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

答案 6 :(得分:1)

以下是迄今为止提供的一些主要变体

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'毒药'后期结果中存在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

答案 7 :(得分:1)

一种方法是使用rollapply中的zoo

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

答案 8 :(得分:1)

派对有点晚了,但我还没有看到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&#39; 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()以删除组名。