Самый быстрый способ найти второе (третье...) наивысшее/наименьшее значение в векторе или столбце

R предлагает max и min, но я не вижу действительно быстрого способа найти другое значение в порядке, отличном от сортировки всего вектора, и выбора значения x из этого вектора.

Есть ли более быстрый способ получить второе наивысшее значение (например)?

Спасибо

Ответ 1

Используйте аргумент partial sort(). Для второго наивысшего значения:

n <- length(x)
sort(x,partial=n-1)[n-1]

Ответ 2

Немного медленная альтернатива, только для записей:

x <- c(12.45,34,4,0,-234,45.6,4)
max( x[x!=max(x)] )
min( x[x!=min(x)] )

Ответ 3

Я обернул Rob ответ на несколько более общую функцию, которая может быть использована для поиска 2-го, 3-го, 4-го (и т.д.) max:

maxN <- function(x, N=2){
  len <- length(x)
  if(N>len){
    warning('N greater than length(x).  Setting N=length(x)')
    N <- length(x)
  }
  sort(x,partial=len-N+1)[len-N+1]
}

maxN(1:10)

Ответ 4

Вот простой способ найти индексы N наименьших/наибольших значений в векторе (пример для N = 3):

N <- 3

N Наименьшее:

ndx <- order(x)[1:N]

N Наибольшее:

ndx <- order(x, decreasing = T)[1:N]

Итак, вы можете извлечь значения как:

x[ndx]

Ответ 5

Rfast имеет функцию nth_element, которая выполняет именно то, что вы просите, и работает быстрее, чем все реализации, описанные выше

Также рассмотренные выше методы, основанные на частичной сортировке, не поддерживают поиск наименьших значений.

Rfast::nth(x, 5, descending = T)

Вернет 5-й по величине элемент x, а

Rfast::nth(x, 5, descending = F)

Вернет 5-й наименьший элемент x

Приведенные ниже критерии для сравнения с наиболее популярными ответами.

Для 10 тысяч номеров:

N = 10000
x = rnorm(N)

maxN <- function(x, N=2){
    len <- length(x)
    if(N>len){
        warning('N greater than length(x).  Setting N=length(x)')
        N <- length(x)
    }
    sort(x,partial=len-N+1)[len-N+1]
}

microbenchmark::microbenchmark(
    Rfast = Rfast::nth(x,5,descending = T),
    maxn = maxN(x,5),
    order = x[order(x, decreasing = T)[5]]
)

Unit: microseconds
  expr      min       lq      mean   median        uq       max neval
 Rfast  160.364  179.607  202.8024  194.575  210.1830   351.517   100
  maxN  396.419  423.360  559.2707  446.452  487.0775  4949.452   100
 order 1288.466 1343.417 1746.7627 1433.221 1500.7865 13768.148   100

Для 1 миллиона номеров:

N = 1e6 #evaluates to 1 million
x = rnorm(N)

microbenchmark::microbenchmark(
    Rfast = Rfast::nth(x,5,descending = T),
    maxN = maxN(x,5),
    order = x[order(x, decreasing = T)[5]]
)

Unit: milliseconds
  expr      min        lq      mean   median        uq       max neval
 Rfast  89.7722  93.63674  114.9893 104.6325  120.5767  204.8839   100
  maxN 150.2822 207.03922  235.3037 241.7604  259.7476  336.7051   100
 order 930.8924 968.54785 1005.5487 991.7995 1031.0290 1164.9129   100

Ответ 6

Для n-го наивысшего значения

sort(x, TRUE)[n]

Ответ 7

Я обнаружил, что сначала удаляет максимальный элемент, а затем выполняет еще один макс, сравнимый со скоростью:

system.time({a=runif(1000000);m=max(a);i=which.max(a);b=a[-i];max(b)})
   user  system elapsed 
  0.092   0.000   0.659 

system.time({a=runif(1000000);n=length(a);sort(a,partial=n-1)[n-1]})
   user  system elapsed 
  0.096   0.000   0.653 

Ответ 8

Когда я недавно искал функцию R, возвращающую индексы верхних номеров N max/min в заданном векторе, я был удивлен, что такой функции нет.

И это что-то очень похожее.

Решение грубой силы с использованием функции base:: order представляется наиболее простым.

topMaxUsingFullSort <- function(x, N) {
  sort(x, decreasing = TRUE)[1:min(N, length(x))]
}

Но это не самый быстрый, если ваше значение N относительно невелико по сравнению с длиной вектора x.

С другой стороны, если N действительно мал, вы можете использовать функцию base:: whichMax итеративно, и на каждой итерации вы можете заменить найденное значение на -Inf

# the input vector 'x' must not contain -Inf value 
topMaxUsingWhichMax <- function(x, N) {
  vals <- c()
  for(i in 1:min(N, length(x))) {
    idx      <- which.max(x)
    vals     <- c(vals, x[idx]) # copy-on-modify (this is not an issue because idxs is relative small vector)
    x[idx]   <- -Inf            # copy-on-modify (this is the issue because data vector could be huge)
  }
  vals
}

Я считаю, что вы видите проблему - природу R. copy-on-modify. Таким образом, это будет работать лучше для очень очень маленького N (1,2,3), но оно будет быстро замедляться для больших значений N. И вы выполняете итерацию по всем элементам в векторе x N.

Я думаю, что лучшим решением в чистом R является использование частичного base:: sort.

topMaxUsingPartialSort <- function(x, N) {
  N <- min(N, length(x))
  x[x >= -sort(-x, partial=N)[N]][1:N]
}

Затем вы можете выбрать последний ( N th) элемент из результата функций, описанных выше.

Примечание: функции, описанные выше, являются просто примерами - если вы хотите их использовать, вам нужно проверить/ввести необходимые значения (например, N > длина (x)).

Я написал небольшую статью о чем-то очень похожем (получите индексы верхних значений N max/min для вектора) в http://palusga.cz/?p=18 - вы можете найти здесь некоторые ориентиры аналогичных функций, определенных выше.

Ответ 9

head(sort(x),..) или tail(sort(x),...) должны работать

Ответ 10

topn = function(vector, n){
  maxs=c()
  ind=c()
  for (i in 1:n){
    biggest=match(max(vector), vector)
    ind[i]=biggest
    maxs[i]=max(vector)
    vector=vector[-biggest]
  }
  mat=cbind(maxs, ind)
  return(mat)
}

эта функция вернет матрицу с верхними значениями n и их индексами. Надеюсь, поможет VDevi-Chou

Ответ 11

Здесь будет найден индекс наименьшего или наибольшего значения N во входном числовом векторе x. Установите bottom = TRUE в аргументах, если вы хотите, чтобы N'th снизу, или bottom = FALSE, если вы хотите, чтобы N'th сверху. N = 1 и bottom = TRUE эквивалентно тому, что .min, N = 1, а bottom = FALSE эквивалентно тому, что .max.

FindIndicesBottomTopN <- function(x=c(4,-2,5,-77,99),N=1,bottom=FALSE)
{

  k1 <- rank(x)
  if(bottom==TRUE){
    Nindex <- which(k1==N)
    Nindex <- Nindex[1]
  }

  if(bottom==FALSE){
    Nindex <- which(k1==(length(x)+1-N))
    Nindex <- Nindex[1]
  }

  return(Nindex)
}

Ответ 12

У dplyr есть функция nth, где первый аргумент - это вектор, а второй - место, которое вы хотите. Это касается и повторяющихся элементов. Например:

x = c(1,2, 8, 16, 17, 20, 1, 20)

Нахождение второго по величине значения:

 nth(unique(x),length(unique(x))-1)

[1] 17

Ответ 13

Вы можете определить следующее более высокое значение с помощью cummax(). Если вы хотите, чтобы местоположение каждого нового более высокого значения, например, вы могли передать свой вектор значений cummax() в функцию diff() для определения местоположений, в которых значение cummax() изменилось. скажем, мы имеем вектор

v <- c(4,6,3,2,-5,6,8,12,16)
cummax(v) will give us the vector
4  6  6  6  6  6  8 12 16

Теперь, если вы хотите найти местоположение изменения в cummax(), у вас есть много вариантов, я склонен использовать sign(diff(cummax(v))). Вы должны отрегулировать потерянный первый элемент из-за diff(). Полный код для вектора v будет:

which(sign(diff(cummax(v)))==1)+1

Ответ 14

Вы можете использовать ключевое слово sort следующим образом:

sort(unique(c))[1:N]

Пример:

c <- c(4,2,44,2,1,45,34,2,4,22,244)
sort(unique(c), decreasing = TRUE)[1:5]

даст первые 5 максимальных чисел.