不确定这是否更快,但我们可以使用findInterval 将x 剪切为thresholds。我们使用tapply 取每组的sum 并反过来取cumsum。
as.integer(rev(cumsum(rev(tapply(x,
findInterval(x, thresholds, left.open = TRUE), sum)[-1]))))
经过测试
thresholds <- c(3, 5, 10)
x <- c(2, 3, 1, 19, 4, 6, 5, 15, 7:14, 16:18, 20) #1:20 in random order
vec_sum <- rep(NA,length(thresholds))
for(i in seq_along(thresholds)) {
vec_sum[i] <- sum(x[x>thresholds[i]])
}
vec_sum
#[1] 204 195 155
使用建议的解决方案
as.integer(rev(cumsum(rev(tapply(x,
findInterval(x, thresholds, left.open = TRUE), sum)[-1]))))
#[1] 204 195 155
解释答案。 findInterval 返回 x 的每个值所属的组
findInterval(x, thresholds, left.open = TRUE)
#[1] 0 0 0 3 1 2 1 3 2 2 2 2 3 3 3 3 3 3 3 3
我们使用tapply得到每个组的sum
tapply(x, findInterval(x, thresholds, left.open = TRUE), sum)
# 0 1 2 3
# 6 9 40 155
0-group 应该被排除,因为它们小于threshold 的所有值(因此-1)。第 2 组也应该包含第 1 组的总和,第 3 组应该包含第 1 组和第 2 组的总和。所以我们reverse 序列并采用cumsum
cumsum(rev(tapply(x, findInterval(x, thresholds, left.open = TRUE), sum)[-1]))
# 3 2 1
#155 195 204
为了以原始顺序获取它并与threshold匹配,我们再次reverse
rev(cumsum(rev(tapply(x, findInterval(x, thresholds, left.open = TRUE), sum)[-1])))
# 1 2 3
#204 195 155
边缘案例:
如果所有值都低于阈值或所有值都高于阈值,我们可能需要进行额外检查并返回以下内容。
if (all(x < thresholds[1])) rep(0, length(thresholds))
if (all(x > thresholds[length(thresholds)])) rep(sum(x), length(thresholds))