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
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]
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)] )
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)
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]
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
Pour la nième valeur la plus élevée,
sort(x, TRUE)[n]
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
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.
head(sort(x),..)
ou tail(sort(x),...)
devrait fonctionner
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
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
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)
}