以下是目前提供的一些主要变体:
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) {
unname(tapply(v, (seq_along(v)-1) %/% n, sum, na.rm=na.rm))
}
f2 <- function(v, n, na.rm=TRUE) {
nv <- length(v)
if (nv %% n)
v[ceiling(nv / n) * n] <- NA
colSums(matrix(v, n), na.rm=na.rm)
}
f3 <- function(v, n) {
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
累加方法
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
length(v)
能够被n
整除时才有效。否则,向量循环将会影响你的结果。(例如,v <- 1:3; n <- 2; matrix(v, nrow=n)
。) - Josh O'Brienmatrix(..., byrow=TRUE)
的情况下才能工作,因此 @Andrie 的答案中使用了colSums
而不是rowSums
。 - plannapus