Ответы:
В Rfast есть функция nth_element, которая делает именно то, что вы просите, и работает быстрее, чем все реализации, описанные выше.
Также рассмотренные выше методы, основанные на частичной сортировке, не поддерживают поиск k наименьших значений
Rfast::nth(x, 5, descending = T)
Вернет 5-й по величине элемент х, в то время как
Rfast::nth(x, 5, descending = F)
Вернет 5-й самый маленький элемент х
Приведенные ниже контрольные показатели в отношении наиболее популярных ответов.
Для 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
Rfast::nth
может возвращать несколько элементов (например, 8-й и 9-й по величине элементы), а также индексы этих элементов.
Используйте partial
аргумент sort()
. Для второго по величине значения:
n <- length(x)
sort(x,partial=n-1)[n-1]
sort(x, TRUE)[2]
что описано в ответе @ Abrar, помимо несоблюдения ограничения в вопросе?
Error in sort.int(x, na.last = na.last, decreasing = decreasing, ...) : index 4705 outside bounds
Любая идея, в чем может быть проблема? Некоторые детали: My x - это числовой вектор длиной 4706 с некоторыми NA
s в данных. Я попытался получить второе по величине значение в векторе, используя тот же код, который предложил @RobHyndman.
decreasing
аргумент не совместим с частичной сортировкой, вы всегда можете -sort(-x, partial=n-1)[n-1]
; это логически то же самое и занимает значительно меньше времени, чем sort(x, decreasing=TRUE)[n-1]
.
Немного более медленная альтернатива, только для записей:
x <- c(12.45,34,4,0,-234,45.6,4)
max( x[x!=max(x)] )
min( x[x!=min(x)] )
max(x[-which.max(x)])
Я обернул ответ Роба в чуть более общую функцию, которую можно использовать, чтобы найти 2-й, 3-й, 4-й (и т. Д.) Максимум:
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)
maxN(1:10, 1:3)
(я бы по умолчанию установил N на 1)
Вот простой способ найти индексы N самых маленьких / самых больших значений в векторе (пример для N = 3):
N <- 3
N Наименьший:
ndx <- order(x)[1:N]
N Largest:
ndx <- order(x, decreasing = T)[1:N]
Таким образом, вы можете извлечь значения как:
x[ndx]
Для n-го наивысшего значения,
sort(x, TRUE)[n]
Я обнаружил, что сначала удаляем элемент max, а затем выполняем еще один максимальный прогон с сопоставимой скоростью:
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
Вот самый простой способ, который я нашел,
num <- c(5665,1615,5154,65564,69895646)
num <- sort(num, decreasing = F)
tail(num, 1) # Highest number
head(tail(num, 2),1) # Second Highest number
head(tail(num, 3),1) # Third Highest number
head(tail(num, n),1) # Generl equation for finding nth Highest number
Когда я недавно искал 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. Таким образом, это будет работать лучше для очень очень очень малого 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- й) элемент из результата функций, описанных выше.
Примечание: функции, определенные выше, являются просто примерами - если вы хотите использовать их, вы должны проверить / рассудить входные данные (например, N> length (x) ).
Я написал небольшую статью о чем-то очень похожем (получить индексы верхних значений N max / min вектора) по адресу http://palusga.cz/?p=18 - здесь вы можете найти некоторые тесты аналогичных функций, которые я определил выше.
head(sort(x),..)
или tail(sort(x),...)
должен работать
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
Это найдет индекс N-го наименьшего или наибольшего значения во входном числовом векторе x. Установите bottom = TRUE в аргументах, если вы хотите, чтобы N-е снизу, или bottom = FALSE, если вы хотите, чтобы N-й сверху. N = 1 и bottom = TRUE эквивалентны which.min, N = 1 и bottom = FALSE эквивалентны which.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)
}
У dplyr есть функция nth, где первый аргумент - вектор, а второй - место, которое вы хотите. Это касается и повторяющихся элементов. Например:
x = c(1,2, 8, 16, 17, 20, 1, 20)
Нахождение второго по величине значения:
nth(unique(x),length(unique(x))-1)
[1] 17
x[[order(order_by)[[n]]]]
- так что требуется сортировка всего вектора. Так что это будет не так быстро, как принятый ответ.
sort
с аргументом частичного = (который меняет все)
dplyr::nth()
? bench::mark(max(x[-which.max(x)]), x[[order(-x)[[2]]]] )
, nth()
Кажется , почти в 10 раз медленнее, где length(x)
есть 3 миллиона человек .
Вы можете идентифицировать следующее более высокое значение с 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
Вы можете использовать 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 максимальных чисел.
topn
функцию , которая быстрееsort
,order
иnth
. Посмотри документацию.