web-dev-qa-db-fra.com

Moyen le plus rapide de trouver la deuxième (troisième ...) valeur la plus élevée/la plus faible en vecteur ou en colonne

R offre max et min, mais je ne vois pas de moyen très rapide de trouver une autre valeur dans l’ordre, à part trier le vecteur entier et choisir la valeur x à partir de ce vecteur.

Existe-t-il un moyen plus rapide d’obtenir la deuxième valeur la plus élevée (par exemple)?

Merci

146
jorgusch

Utilisez l'argument partial de sort(). Pour la deuxième valeur la plus élevée:

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

Alternative légèrement plus lente, juste pour les enregistrements:

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

J'ai résumé la réponse de Rob dans une fonction légèrement plus générale, qui peut être utilisée pour trouver le 2e, 3e, 4e (etc.) maximum

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)
27
Zach

Voici un moyen facile de trouver les indices des N plus petites/valeurs les plus grandes dans un vecteur (Exemple pour N = 3):

N <- 3

N le plus petit:

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

N le plus grand:

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

Vous pouvez donc extraire les valeurs en tant que:

x[ndx]
15
Davit Sargsyan

Rfast a une fonction appelée nth_element qui fait exactement ce que vous demandez et est plus rapide que toutes les implémentations décrites ci-dessus

De plus, les méthodes décrites ci-dessus qui sont basées sur un tri partiel ne permettent pas de trouver les k plus petites valeurs

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

Retourne le 5ème plus grand élément de x, alors que

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

Retourne le 5ème plus petit élément de x

Repères ci-dessous par rapport aux réponses les plus populaires.

Pour 10 mille numéros:

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

Pour 10 million numéros:

N = 1e6
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
10
Stefanos

Pour la nième valeur la plus élevée,

sort(x, TRUE)[n]
4
Abrar

J'ai trouvé que supprimer l'élément max en premier et ensuite faire un autre max fonctionne à une vitesse comparable

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
John Jiang

Lorsque je recherchais récemment une fonction R renvoyant les indices des N premiers nombres max/min d'un vecteur donné, j'ai été surpris de constater qu'il n'existait pas une telle fonction. 

Et c'est quelque chose de très similaire. 

La solution de force brute utilisant la fonction base :: order semble être la plus simple.

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

Mais ce n’est pas le plus rapide au cas où votre valeur N soit relativement petite comparée à la longueur du vecteur x.

De l'autre côté, si le N est vraiment petit, vous pouvez utiliser la fonction base :: whichMax de manière itérative et, à chaque itération, vous pouvez remplacer la valeur trouvée par -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
}

Je crois que vous voyez le problème - la nature de R. de la copie sur modification. Cela fonctionnera donc mieux pour un très très petit N (1,2,3), mais il ralentira rapidement pour des valeurs de N plus grandes. Et vous parcourez tous les éléments du vecteur x _ {N fois.

Je pense que la meilleure solution en R propre consiste à utiliser des partiels base :: sort.

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

Ensuite, vous pouvez sélectionner le dernier (N ème) élément du résultat des fonctions définies ci-dessus.

Remarque: les fonctions définies ci-dessus ne sont que des exemples - si vous voulez les utiliser, vous devez vérifier les entrées/santé (par exemple. N> longueur (x)).

J'ai écrit un petit article sur quelque chose de très similaire (obtenez les index des N principales valeurs max/min d'un vecteur) à http://palusga.cz/?p=18 - vous pouvez trouver ici quelques points de repère de fonctions similaires. J'ai défini ci-dessus.

1
Donarus

head(sort(x),..) ou tail(sort(x),...) devrait fonctionner

1
Job Mangelmans

dplyr a la fonction nth, où le premier argument est le vecteur et le second est l'endroit que vous voulez Cela vaut aussi pour les éléments répétitifs. Par exemple:

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

Trouver la deuxième plus grande valeur:

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

[1] 17
0
Noale
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)
}

cette fonction renverra une matrice avec les n premières valeurs et leurs indices. espérons que cela aide VDevi-Chou

0
vdc320

Ceci trouvera l'indice de la nième valeur la plus petite ou la plus grande dans le vecteur numérique en entrée x. Définissez bottom = TRUE dans les arguments si vous voulez le nième du bas ou bottom = FALSE si vous voulez le nième du haut. N = 1 et bottom = TRUE est équivalent à quel.min, N = 1 et bottom = FALSE est équivalent à quel.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
Ralph