Подтвердить что ты не робот

FindInterval() с правооткрытыми интервалами

Великая функция findInterval() в R использует левые замкнутые поддиапазоны в аргументе vec, как показано в ее документах:

if i <- findInterval(x,v), имеем v[i[j]] <= x[j] < v[i[j] + 1]

Если мне нужны закрытые суб-интервалы, какие у меня варианты? Самое лучшее, что я придумал, это:

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

Еще одна работа:

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

Здесь немного теста:

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

Но я бы хотел увидеть любые другие решения, если там лучший. "Лучше", я имею в виду "как-то более удовлетворительно" или "не чувствует себя клопиком" или, может быть, даже "более эффективным". =)

(Обратите внимание, что есть аргумент rightmost.closed для findInterval(), но он другой - он относится только к окончательному поддиапазону и имеет другое значение.)

4b9b3361

Ответ 1

EDIT: Основная очистка во всех проходах.

Вы можете посмотреть cut. По умолчанию cut делает левые открытые и правые закрытые интервалы и может быть изменен с использованием соответствующего аргумента (right). Чтобы использовать ваш пример:

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

Теперь создайте четыре функции, которые должны сделать то же самое: два из OP, один из Josh O'Brien, а затем cut. Два аргумента для cut были изменены из настроек по умолчанию: include.lowest = TRUE создаст интервал, закрытый с обеих сторон для наименьшего (крайнего) интервала. labels = FALSE приведет к тому, что cut просто вернет целочисленные значения для бункеров вместо создания коэффициента, который он в противном случае делает.

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))
}

Все ли функции возвращают один и тот же результат? Ага. (обратите внимание на использование cutVec для cutFun)

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

Теперь более требовательный вектор к bin:

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

Проверьте, идентичны ли (обратите внимание на использование unname)

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

И контрольный показатель:

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

Из этого прогона cut кажется самым быстрым.

Ответ 2

Возможно, вы можете использовать опцию left.open:

findInterval(x, vec, left.open=T)
[1] 1 2 3 3 3 4 4

Ответ 3

Если ваши лимиты являются интервалами, вы можете просто увеличить правый интервал: интервал + c (0,0.1) будет делать: findinterval (значение, интервал + c (0,0.1))