首页 > 解决方案 > 高于给定阈值的向量值的快速求和

问题描述

我有一个阈值thresholds向量, 和另一个向量,x。我想创建一个新的向量,例如vec_sum,长度与 相同thresholds,它为 的每个元素存储大于该元素thresholds的值的总和。x

最快的方法是什么?我这样做的天真方式是

vec_sum <- rep(NA,length(thresholds))
for(i in seq_along(thresholds))
{
   vec_sum[i] <- sum(x[x>thresholds[i]])
}

如果有帮助,阈值已经排序。

标签: rperformanceloopsvector

解决方案


这是另一个使用的解决方案cumsum

f1 <- function(v, th){
    v2 <- v[order(v)]
    v2s <- rev(cumsum(rev(v2)))
    return(v2s[findInterval(th, v2) + 1])
}

以下是 Ronak 与其他答案(以及示例数据)的一些测试和比较:

f2 <- function(x, thresholds){
    if (all(x < thresholds[1])) return(rep(0, length(thresholds)))
    if (all(x > thresholds[length(thresholds)])) return(rep(sum(x), length(thresholds)))
    return(rev(cumsum(rev(tapply(x, 
        findInterval(x, thresholds, left.open = TRUE), sum)[-1]))))
}

test_th <- c(3, 5, 10)
test_x <- c(2, 3, 1, 19, 4, 6, 5, 15, 7:14, 16:18, 20)

vec_sum <- rep(NA,length(test_th))
for(i in seq_along(test_th)) {
    vec_sum[i] <- sum(test_x[test_x>test_th[i]])
}

all(dplyr::near(f1(test_x, test_th), vec_sum))
# [1] TRUE
all(dplyr::near(f2(test_x, test_th), vec_sum))
# [1] TRUE


set.seed(123)
test_x <- rnorm(10000)
test_th <- sort(rnorm(100)) ## f2 requires sorted threshold values

vec_sum <- rep(NA,length(test_th))
for(i in seq_along(test_th)) {
    vec_sum[i] <- sum(test_x[test_x>test_th[i]])
}
all(dplyr::near(f1(test_x, test_th), vec_sum))
# [1] TRUE
all(dplyr::near(f2(test_x, test_th), vec_sum))
# [1] FALSE
# Warning message:
# In x - y : longer object length is not a multiple of shorter object length

library(microbenchmark)
microbenchmark(
    a = f1(test_x, test_th),
    b = f2(test_x, test_th)
)
# Unit: microseconds
#  expr      min       lq      mean   median       uq       max neval
#     a  587.116  682.864  900.3572  694.713  703.726 10647.206   100
#     b 1157.213 1203.063 1260.0663 1223.600 1258.552  2143.069   100

推荐阅读