2011-02-06 10 views
9

Quando ci sono cravatte nei dati originali, c'è un modo per creare una classifica senza spazi vuoti (valori di classifica interi consecutivi)? Supponiamo che:Come ottenere ranghi senza spazi vuoti quando ci sono legami tra i valori?

x <- c(10, 10, 10, 5, 5, 20, 20) 
rank(x) 
# [1] 4.0 4.0 4.0 1.5 1.5 6.5 6.5 

In questo caso il risultato desiderato sarebbe:

my_rank(x) 
[1] 2 2 2 1 1 3 3 

Ho giocato con tutte le opzioni per ties.method opzione (average, max, min, random), nessuno dei quali sono progettato per fornire il risultato desiderato.

È possibile ottenerlo con la funzione rank()?

risposta

3

Posso pensare a una funzione rapida per farlo. Non è ottimale con un ciclo for ma funziona :)

x=c(1,1,2,3,4,5,8,8) 

foo <- function(x){ 
    su=sort(unique(x)) 
    for (i in 1:length(su)) x[x==su[i]] = i 
    return(x) 
} 

foo(x) 

[1] 1 1 2 3 4 5 6 6 
+0

Questo funziona meravigliosamente. Grazie. Inoltre, è molto semplice cambiare la direzione dell'ordinamento se hai bisogno di un rank decrescente! Saluti! –

0

Che dire sort()?

x <- c(1,1,2,3,4,5) 
sort(x) 

> sort(x) 
[1] 1 1 2 3 4 5 
+0

Questo è corretto per coincidenza. I numeri non sono puliti come nell'esempio. vale a dire. prova: x <- c (0.5,0.56,0.76,0.23,0.33,0.4) –

+0

@Brandon - Forse non sto comprendendo alcune restrizioni del tuo bisogno qui ... probabilmente questa parte "Non posso avere due elementi in entrambe le estremità dell'intervallo sono maggiori di 1 o massimo (intervallo). " Qual è l'output desiderato dal tuo esempio nel commento sopra? Se questo è più rappresentativo di quello che è nella tua domanda, forse potresti modificare la domanda per riflettere questo? – Chase

+0

scuse se non fosse chiaro. La domanda riguarda il posizionamento dei dati e quello che hai fatto qui fornisce una sorta di dati che capita anche di essere la stessa sequenza di numeri che deriverebbero dalla soluzione di classificazione che sto cercando di ottenere. L'obiettivo è ottenere i gradi, non solo l'ordinamento. –

6

Il modo "loopless" per farlo è quello di trattare semplicemente il vettore come fattore ordinata, quindi convertirlo in numerico:

> as.numeric(ordered(c(10,10,10,10, 5,5,5, 10, 10))) 
[1] 2 2 2 2 1 1 1 2 2 
> as.numeric(ordered(c(0.5,0.56,0.76,0.23,0.33,0.4))) 
[1] 4 5 6 1 2 3 
> as.numeric(ordered(c(1,1,2,3,4,5,8,8))) 
[1] 1 1 2 3 4 5 6 6 

Aggiornamento: Un altro modo, che sembra più veloce è utilizzare findInterval e sort(unique()):

> x <- c(10, 10, 10, 10, 5,5,5, 10, 10) 
> findInterval(x, sort(unique(x))) 
[1] 2 2 2 2 1 1 1 2 2 

> x <- round(abs(rnorm(1000000)*10)) 
> system.time(z <- as.numeric(ordered(x))) 
    user system elapsed 
    0.996 0.025 1.021 
> system.time(z <- findInterval(x, sort(unique(x)))) 
    user system elapsed 
    0.077 0.003 0.080 
1

Un'altra funzione che fa questo, ma sembra inefficiente. Non c'è il ciclo for, ma dubito che sia più efficiente del suggerimento di Sacha!

x=c(1,1,2,3,4,5,8,8) 
fancy.rank <- function(x) { 
    x.unique <- unique(x) 
    d1 <- data.frame(x=x) 
    d2 <- data.frame(x=x.unique, rank(x.unique)) 
    merge(d1, d2, by="x")[,2] 
} 

fancy.rank(x) 

[1] 1 1 2 3 4 5 6 6 
12

Modificato crayola solution ma uing match invece di merge:

x_unique <- unique(x) 
x_ranks <- rank(x_unique) 
x_ranks[match(x,x_unique)] 
+0

Eccellente! A quanto pare sembra (benchmark con rep (x, 100000)) che questa sia la soluzione più veloce.Fondamentalmente: Marek> Prasad (rivisto)> Chase> Prasad (prima)> Crayola (in termini di velocità) – crayola

+6

Si può fare tutto in una riga: 'match (x, sort (unique (x)))' – hadley

+1

@hadley Come sempre hai ragione;) Ho trovato questa soluzione dopo la pubblicazione, ma i tempi erano sorprendenti, quindi tengo aggiornato. – Marek

0

Provate a pensare a un altro modo

x <- c(10,10,10,5,5,20,20) 
as.numeric(as.factor(x)) 
[1] 2 2 2 1 1 3 3 
Problemi correlati