我有一个向量,我需要对每个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
答案 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()
以删除组名。