Ответ 1
Используйте аргумент partial
sort()
. Для второго наивысшего значения:
n <- length(x)
sort(x,partial=n-1)[n-1]
R предлагает max и min, но я не вижу действительно быстрого способа найти другое значение в порядке, отличном от сортировки всего вектора, и выбора значения x из этого вектора.
Есть ли более быстрый способ получить второе наивысшее значение (например)?
Спасибо
Используйте аргумент partial
sort()
. Для второго наивысшего значения:
n <- length(x)
sort(x,partial=n-1)[n-1]
Немного медленная альтернатива, только для записей:
x <- c(12.45,34,4,0,-234,45.6,4)
max( x[x!=max(x)] )
min( x[x!=min(x)] )
Я обернул 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)
Вот простой способ найти индексы N наименьших/наибольших значений в векторе (пример для N = 3):
N <- 3
N Наименьшее:
ndx <- order(x)[1:N]
N Наибольшее:
ndx <- order(x, decreasing = T)[1:N]
Итак, вы можете извлечь значения как:
x[ndx]
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
Для n-го наивысшего значения
sort(x, TRUE)[n]
Я обнаружил, что сначала удаляет максимальный элемент, а затем выполняет еще один макс, сравнимый со скоростью:
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
Когда я недавно искал функцию 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 - вы можете найти здесь некоторые ориентиры аналогичных функций, определенных выше.
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'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)
}
У dplyr есть функция nth, где первый аргумент - это вектор, а второй - место, которое вы хотите. Это касается и повторяющихся элементов. Например:
x = c(1,2, 8, 16, 17, 20, 1, 20)
Нахождение второго по величине значения:
nth(unique(x),length(unique(x))-1)
[1] 17
Вы можете определить следующее более высокое значение с помощью 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 максимальных чисел.