Risposte:
Rfast ha una funzione chiamata nth_element che fa esattamente quello che chiedi ed è più veloce di tutte le implementazioni discusse sopra
Anche i metodi discussi sopra che si basano su un ordinamento parziale, non supportano la ricerca dei k valori più piccoli
Rfast::nth(x, 5, descending = T)
Restituirà il quinto elemento più grande di x, mentre
Rfast::nth(x, 5, descending = F)
Restituirà il quinto elemento più piccolo di x
Di seguito i benchmark contro le risposte più popolari.
Per 10 mila numeri:
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
Per 1 milione di numeri:
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
può restituire più elementi (ad esempio 8 ° e 9 ° elemento più grande) nonché gli indici di tali elementi.
Usa l' partial
argomento di sort()
. Per il secondo valore più alto:
n <- length(x)
sort(x,partial=n-1)[n-1]
sort(x, TRUE)[2]
quello descritto nella risposta di @ Abrar, oltre a non soddisfare il vincolo della domanda?
Error in sort.int(x, na.last = na.last, decreasing = decreasing, ...) : index 4705 outside bounds
Hai idea di quale potrebbe essere il problema? Alcuni dettagli: la mia x è un vettore numerico di lunghezza 4706 con alcuni NA
s nei dati. Ho cercato di ottenere il secondo valore più alto nel vettore usando lo stesso codice suggerito da @RobHyndman.
decreasing
argomento non sia compatibile con l'ordinamento parziale, è sempre possibile -sort(-x, partial=n-1)[n-1]
; è logicamente la stessa cosa e richiede molto meno tempo di sort(x, decreasing=TRUE)[n-1]
.
Alternativa leggermente più lenta, solo per i record:
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)])
Ho racchiuso la risposta di Rob in una funzione leggermente più generale, che può essere utilizzata per trovare il 2 °, 3 °, 4 ° (ecc.) Massimo:
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)
(avrei impostato N predefinito su 1)
Ecco un modo semplice per trovare gli indici di N valori più piccoli / più grandi in un vettore (Esempio per N = 3):
N <- 3
N più piccolo:
ndx <- order(x)[1:N]
N più grande:
ndx <- order(x, decreasing = T)[1:N]
Quindi puoi estrarre i valori come:
x[ndx]
Per l'ennesimo valore più alto,
sort(x, TRUE)[n]
Ho scoperto che rimuovendo prima l'elemento max e poi eseguendo un'altra corsa max a velocità comparabile:
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
Ecco il modo più semplice che ho trovato,
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
Quando di recente stavo cercando una funzione R che restituisse gli indici dei primi N numeri max / min in un dato vettore, sono rimasto sorpreso che non esistesse una tale funzione.
E questo è qualcosa di molto simile.
La soluzione di forza bruta che utilizza la funzione base :: order sembra essere la più semplice.
topMaxUsingFullSort <- function(x, N) {
sort(x, decreasing = TRUE)[1:min(N, length(x))]
}
Ma non è il più veloce nel caso in cui il tuo valore N sia relativamente piccolo rispetto alla lunghezza del vettore x .
D'altra parte se la N è veramente piccola, puoi usare la base :: whichMax in modo iterativo e in ogni iterazione puoi sostituire il valore trovato con -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
}
Credo che tu veda il problema - la natura della copia su modifica di R. Quindi, questo funzionerà meglio per N (1,2,3) molto molto molto piccolo, ma rallenterà rapidamente per valori N più grandi. E stai ripetendo tutti gli elementi nel vettore x N volte.
Penso che la soluzione migliore in R pulita sia usare la base :: ordinamento parziale .
topMaxUsingPartialSort <- function(x, N) {
N <- min(N, length(x))
x[x >= -sort(-x, partial=N)[N]][1:N]
}
Quindi è possibile selezionare l'ultimo ( N esimo) elemento dal risultato delle funzioni di cui sopra.
Nota: le funzioni sopra definite sono solo esempi - se si desidera utilizzarle, è necessario controllare gli ingressi / sanità (ad es. N> lunghezza (x) ).
Ho scritto un piccolo articolo su qualcosa di molto simile (ottieni indici dei migliori valori N / max di un vettore) su http://palusga.cz/?p=18 - puoi trovare qui alcuni parametri di riferimento di funzioni simili che ho definito sopra.
head(sort(x),..)
o tail(sort(x),...)
dovrebbe funzionare
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)
}
questa funzione restituirà una matrice con i primi n valori e i loro indici. spero che aiuti VDevi-Chou
Questo troverà l'indice dell'ennesimo valore più piccolo o più grande nel vettore numerico di input x. Impostare bottom = TRUE negli argomenti se si desidera l'N'th dal basso, oppure bottom = FALSE se si desidera l'N'th dall'alto. N = 1 e bottom = TRUE è equivalente a which.min, N = 1 e bottom = FALSE è equivalente a who.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 ha la funzione nth, in cui il primo argomento è il vettore e il secondo è il posto desiderato. Questo vale anche per gli elementi ripetuti. Per esempio:
x = c(1,2, 8, 16, 17, 20, 1, 20)
Trovare il secondo valore più grande:
nth(unique(x),length(unique(x))-1)
[1] 17
x[[order(order_by)[[n]]]]
- quindi richiede l'ordinamento dell'intero vettore. Quindi non sarà veloce come la risposta accettata.
sort
con l'argomento partial = (che cambia tutto)
dplyr::nth()
? bench::mark(max(x[-which.max(x)]), x[[order(-x)[[2]]]] )
, nth()
sembra quasi 10 volte più lento, dove length(x)
sono 3 milioni.
È possibile identificare il valore più alto successivo con cummax()
. Se ad esempio si desidera la posizione di ciascun nuovo valore più alto, è possibile passare il vettore di cummax()
valori alla diff()
funzione per identificare le posizioni in cui il cummax()
valore è cambiato. diciamo che abbiamo il vettore
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
Ora, se vuoi trovare la posizione di un cambiamento, cummax()
hai molte opzioni che tendo a usare sign(diff(cummax(v)))
. Devi regolare il primo elemento perso a causa di diff()
. Il codice completo per il vettore v
sarebbe:
which(sign(diff(cummax(v)))==1)+1
Puoi usare la sort
parola chiave in questo modo:
sort(unique(c))[1:N]
Esempio:
c <- c(4,2,44,2,1,45,34,2,4,22,244)
sort(unique(c), decreasing = TRUE)[1:5]
darà i primi 5 numeri massimi.
topn
funzione che è più veloce disort
,order
enth
. Guarda la documentazione.