Je ne suis pas sûr que ce soit plus rapide, mais nous pouvons utiliser findInterval
pour couper x
por thresholds
. Nous prenons sum
de chaque groupe en utilisant tapply
et prendre cumsum
à l'envers.
as.integer(rev(cumsum(rev(tapply(x,
findInterval(x, thresholds, left.open = TRUE), sum)[-1]))))
Testé sur
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
Utilisation de la solution proposée
as.integer(rev(cumsum(rev(tapply(x,
findInterval(x, thresholds, left.open = TRUE), sum)[-1]))))
#[1] 204 195 155
Expliquer la réponse. findInterval
renvoie des groupes où chaque valeur de x
appartient à
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
Nous utilisons tapply
pour obtenir sum
de chaque groupe
tapply(x, findInterval(x, thresholds, left.open = TRUE), sum)
# 0 1 2 3
# 6 9 40 155
du groupe 0 doivent être exclues car elles sont plus petites que toutes les valeurs de threshold
(d'où -1
). Le groupe 2 doit également contenir la somme du groupe 1 et le groupe 3 doit contenir la somme des groupes 1 et 2. Ainsi, nous rev
erse la séquence et prend cumsum
cumsum(rev(tapply(x, findInterval(x, thresholds, left.open = TRUE), sum)[-1]))
# 3 2 1
#155 195 204
Pour le remettre en état et le faire correspondre à l'original. threshold
nous rev
Encore une fois
rev(cumsum(rev(tapply(x, findInterval(x, thresholds, left.open = TRUE), sum)[-1])))
# 1 2 3
#204 195 155
Cas limites :
S'il y a toutes les valeurs en dessous du seuil ou toutes les valeurs au-dessus du seuil, nous devrons peut-être faire une vérification supplémentaire et retourner ce qui suit.
if (all(x < thresholds[1])) rep(0, length(thresholds))
if (all(x > thresholds[length(thresholds)])) rep(sum(x), length(thresholds))