findInterval () avec des intervalles fermés à droite

Le grand findInterval() fonction dans R gauche-fermé en sous-intervalles dans son vec argument, comme montré dans ses docs:

si i <- findInterval(x,v) nous avons v[i[j]] <= x[j] < v[i[j] + 1]

si je veux des sous-intervalles droits-fermés, quelles sont mes options? Le meilleur que j'ai trouvé c'est ça:

findInterval.rightClosed <- function(x, vec, ...) {
  fi <- findInterval(x, vec, ...)
  fi - (x==vec[fi])
}

un Autre travaille aussi:

findInterval.rightClosed2 <- function(x, vec, ...) {
  length(vec) - findInterval(-x, -rev(vec), ...)
}

Voici un petit test:

x <- c(3, 6, 7, 7, 29, 37, 52)
vec <- c(2, 5, 6, 35)
findInterval(x, vec)
# [1] 1 3 3 3 3 4 4
findInterval.rightClosed(x, vec)
# [1] 1 2 3 3 3 4 4
findInterval.rightClosed2(x, vec)
# [1] 1 2 3 3 3 4 4

mais j'aimerais voir d'autres solutions s'il y a une meilleure un. Par "mieux", je veux dire" plus satisfaisant "ou" ne ressemble pas à un kludge "ou peut-être même"plus efficace". =)

(notez qu'il y a un rightmost.closed argument findInterval(), mais c'est différent - cela se réfère seulement au dernier sous-intervalle et a un sens différent.)

18
demandé sur Ken Williams 2012-11-21 01:54:31

3 réponses

EDIT: nettoyage majeur dans toutes les allées.

Vous pourriez regarder cut. Par défaut, cut rend gauche ouverte et droite des intervalles fermés, et qui peuvent être changés en utilisant l'argument approprié (right). Pour utiliser votre exemple:

x <- c(3, 6, 7, 7, 29, 37, 52)
vec <- c(2, 5, 6, 35)
cutVec <- c(vec, max(x)) # for cut, range of vec should cover all of x

maintenant, créez quatre fonctions qui devraient faire la même chose: deux de L'OP, une de Josh O'Brien, et puis cut. Deux arguments pour cut ont été changés des paramètres par défaut:include.lowest = TRUE va créer un intervalle fermé des deux côtés pour le plus petit (le plus à gauche) intervalle. labels = FALSE causera cut pour retourner simplement les valeurs entières des bins au lieu de créer un facteur, ce qui est le cas.

findInterval.rightClosed <- function(x, vec, ...) {
  fi <- findInterval(x, vec, ...)
  fi - (x==vec[fi])
}
findInterval.rightClosed2 <- function(x, vec, ...) {
  length(vec) - findInterval(-x, -rev(vec), ...)
}
cutFun <- function(x, vec){
    cut(x, vec, include.lowest = TRUE, labels = FALSE)
}
# The body of fiFun is a contribution by Josh O'Brien that got fed to the ether.
fiFun <- function(x, vec){
    xxFI <- findInterval(x, vec * (1 + .Machine$double.eps))
}

est-ce que toutes les fonctions renvoient le même résultat? Yup. (notez l'utilisation de cutVeccutFun)

mapply(identical, list(findInterval.rightClosed(x, vec)),
  list(findInterval.rightClosed2(x, vec), cutFun(x, cutVec), fiFun(x, vec)))
# [1] TRUE TRUE TRUE

maintenant un vecteur plus exigeant à bin:

x <- rpois(2e6, 10)
vec <- c(-Inf, quantile(x, seq(.2, 1, .2)))

tester si identique (noter l'utilisation de unname)

mapply(identical, list(unname(findInterval.rightClosed(x, vec))),
  list(findInterval.rightClosed2(x, vec), cutFun(x, vec), fiFun(x, vec)))
# [1] TRUE TRUE TRUE

Et référence:

library(microbenchmark)
microbenchmark(findInterval.rightClosed(x, vec), findInterval.rightClosed2(x, vec),
  cutFun(x, vec), fiFun(x, vec), times = 50)
# Unit: milliseconds
#                                expr       min        lq    median        uq       max
# 1                    cutFun(x, vec)  35.46261  35.63435  35.81233  36.68036  53.52078
# 2                     fiFun(x, vec)  51.30158  51.69391  52.24277  53.69253  67.09433
# 3  findInterval.rightClosed(x, vec) 124.57110 133.99315 142.06567 155.68592 176.43291
# 4 findInterval.rightClosed2(x, vec)  79.81685  82.01025  86.20182  95.65368 108.51624

à Partir de ce terme, cut semble être le plus rapide.

10
répondu BenBarnes 2012-11-21 06:46:47

peut-être que vous pouvez utiliser l'option gauche.ouvert:

findInterval(x, vec, left.open=T)
[1] 1 2 3 3 3 4 4
1
répondu dabsingh 2017-10-23 16:33:18

si vos limites sont des intervalles, vous pouvez tout simplement augmenter un peu l'intervalle de droite: intervalle+c(0,0.1) ferait: findinterval(valeur, Intervalle+c(0,0.1))--1-->

-1
répondu Albert Ros 2016-08-15 14:38:33