Najszybszy sposób znalezienia drugiej (trzeciej...) najwyższej / najniższej wartości w wektorze lub kolumnie

R oferuje max i min, ale nie widzę naprawdę szybkiego sposobu na znalezienie innej wartości w kolejności oprócz sortowania całego wektora I niż wybranie wartości x z tego wektora.

Czy istnieje szybszy sposób na uzyskanie drugiej najwyższej wartości (np.)?

Thanks

 136
Author: jogo, 2010-03-16

13 answers

Użyj argumentu partial z sort(). Dla drugiej najwyższej wartości:

n <- length(x)
sort(x,partial=n-1)[n-1]
 171
Author: Rob Hyndman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-16 10:41:24

Nieco wolniejsza alternatywa, tylko dla płyt:

x <- c(12.45,34,4,0,-234,45.6,4)
max( x[x!=max(x)] )
min( x[x!=min(x)] )
 44
Author: Paolo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-16 11:49:31

Owinąłem odpowiedź Roba w nieco bardziej ogólną funkcję, która może być użyta do znalezienia 2., 3., 4. (itd."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)
 25
Author: Zach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-08 19:47:39

Oto prosty sposób na znalezienie indeksów N najmniejszych / największych wartości w wektorze(przykład dla N = 3):

N <- 3

N Najmniejszy:

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

N:

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

Więc możesz wyodrębnić wartości jako:

x[ndx]
 13
Author: Davit Sargsyan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-26 15:38:28

Dla n-tej najwyższej wartości,

sort(x, TRUE)[n]
 4
Author: Abrar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-15 08:15:02

Stwierdziłem, że najpierw usuwam element max, a potem wykonuję kolejny max działa z porównywalną prędkością:

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 
 3
Author: John Jiang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-23 19:03:04

Kiedy ostatnio Szukałem R funkcji zwracającej indeksy top N max/min liczb w danym wektorze, byłem zaskoczony, że nie ma takiej funkcji.

I to jest coś bardzo podobnego.

Rozwiązanie brute force przy użyciubase::order wydaje się być najprostszym rozwiązaniem.

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

Ale nie jest to najszybszy w przypadku, gdy wartość N jest stosunkowo mała w porównaniu do długości wektora x .

Po drugiej stronie, jeśli N jest naprawdę mały, możesz użyć base::whichmax funkcji iteracyjnie i w każdej iteracji możesz zastąpić znalezioną wartość przez -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
}

Wierzę, że widzisz problem-kopiowanie na modyfikowanie natury R. więc będzie to działać lepiej dla bardzo bardzo bardzo małych N (1,2,3), ale to będzie szybko spowolnić dla większych wartości N. I powtarzasz wszystkie elementy w wektorze x N razy.

Myślę, że najlepszym rozwiązaniem w czystym R jest aby użyć częściowej base:: sort .

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

Następnie możesz wybrać ostatnią (Nth) pozycję z wyniku funkcji.

Uwaga: funkcje zdefiniowane powyżej są tylko przykładami - jeśli chcesz z nich korzystać, musisz sprawdzić / sanity inputs (np. N > długość(x)).

Napisałem mały artykuł o czymś bardzo podobnym (uzyskać indeksy najwyższych n max/min wartości wektora) na http://palusga.cz/?p=18 - znajdziesz tutaj kilka benchmarków podobnych funkcje, które zdefiniowałem powyżej.

 1
Author: Donarus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-06 23:49:03

head(sort(x),..) LUB tail(sort(x),...) powinno działać

 1
Author: Job Mangelmans,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-17 16:57:34
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)
}

Ta funkcja zwróci macierz z najwyższymi wartościami n i ich indeksami. mam nadzieję, że to pomoże VDevi-Chou

 0
Author: vdc320,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-06 13:41:46

To znajdzie indeks N-tej najmniejszej lub największej wartości w wejściowym wektorze liczbowym x. Ustaw bottom = TRUE w argumentach, jeśli chcesz n - tą od dołu, lub bottom = FALSE, jeśli chcesz N-tą od góry. N=1 i bottom = TRUE jest równoważne which.min, N=1 i bottom=FALSE jest równoważne 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)
}
 0
Author: Ralph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-31 14:04:40

Możesz zidentyfikować następną wyższą wartość za pomocą cummax(). Jeśli chcesz określić położenie każdej nowej wyższej wartości, na przykład możesz przekazać swój wektor wartości {[2] } do funkcji diff(), aby zidentyfikować miejsca, w których zmieniła się wartość cummax(). powiedzmy, że mamy wektor

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

Teraz, jeśli chcesz znaleźć lokalizację zmiany w cummax() masz wiele opcji, których zwykle używam sign(diff(cummax(v))). Musisz dopasować utracony pierwszy element z powodu diff(). Kompletny kod dla wektora v będzie be:

which(sign(diff(cummax(v)))==1)+1
 -1
Author: user3507767,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-18 16:34:03

Możesz użyć słowa kluczowego sort w następujący sposób:

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

Przykład:

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

Poda pierwsze 5 liczb max.

 -1
Author: Chethanraj Rao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-14 12:15:33

Dplyr ma funkcję nth, gdzie pierwszy argument to wektor, a drugi to miejsce, które chcesz. Dotyczy to również powtarzających się elementów. Na przykład:

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

Znalezienie drugiej co do wielkości wartości:

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

[1] 17
 -1
Author: Noale,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-08 14:51:19