Come ordinare un frame di dati per più colonne


1316

Voglio ordinare un data.frame per più colonne. Ad esempio, con il data.frame in basso, vorrei ordinare per colonna z(decrescente) quindi per colonna b(crescente):

dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"), 
      levels = c("Low", "Med", "Hi"), ordered = TRUE),
      x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
      z = c(1, 1, 1, 2))
dd
    b x y z
1  Hi A 8 1
2 Med D 3 1
3  Hi A 9 1
4 Low C 9 2

Risposte:


1626

Puoi utilizzare la order()funzione direttamente senza ricorrere a strumenti aggiuntivi: vedi questa risposta più semplice che utilizza un trucco direttamente dalla parte superiore del example(order)codice:

R> dd[with(dd, order(-z, b)), ]
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1

Modifica più di 2 anni dopo: è stato appena chiesto come fare per indice di colonna. La risposta è semplicemente passare le colonne di ordinamento desiderate alla order()funzione:

R> dd[order(-dd[,4], dd[,1]), ]
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1
R> 

anziché utilizzare il nome della colonna (e with()per un accesso più facile / più diretto).


@Dirk Eddelbuettel esiste un metodo altrettanto semplice per le matrici?
Jota,

14
Dovrebbe funzionare allo stesso modo, ma non puoi usarlo with. Prova M <- matrix(c(1,2,2,2,3,6,4,5), 4, 2, byrow=FALSE, dimnames=list(NULL, c("a","b")))a creare una matrice M, quindi usa M[order(M[,"a"],-M[,"b"]),]per ordinarla su due colonne.
Dirk Eddelbuettel,

4
Abbastanza facile:, dd[ order(-dd[,4], dd[,1]), ]ma non può essere utilizzato withper il subsetting basato sul nome.
Dirk Eddelbuettel,

18
Ho errore "argomento non valido per operatore unario" durante l'esecuzione del secondo esempio.
Nailgun,

21
L'errore "argomento non valido per l'operatore unario" si verifica quando si utilizza meno con una colonna di caratteri. Risolvilo avvolgendo la colonna xtfrm, ad esempio dd[ order(-xtfrm(dd[,4]), dd[,1]), ].
Richie Cotton,

477

Le tue scelte

  • order a partire dal base
  • arrange a partire dal dplyr
  • setordere setordervdadata.table
  • arrange a partire dal plyr
  • sort a partire dal taRifx
  • orderBy a partire dal doBy
  • sortData a partire dal Deducer

Il più delle volte è necessario utilizzare le soluzioni dplyro data.table, a meno che non sia importante non avere dipendenze, nel qual caso utilizzare base::order.


Di recente ho aggiunto sort.data.frame a un pacchetto CRAN, rendendolo compatibile con la classe come discusso qui: Il modo migliore per creare coerenza generica / di metodo per sort.data.frame?

Pertanto, dato il data.frame dd, è possibile ordinare come segue:

dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"), 
      levels = c("Low", "Med", "Hi"), ordered = TRUE),
      x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
      z = c(1, 1, 1, 2))
library(taRifx)
sort(dd, f= ~ -z + b )

Se sei uno degli autori originali di questa funzione, ti prego di contattarmi. La discussione sul dominio pubblico è qui: http://chat.stackoverflow.com/transcript/message/1094290#1094290


Puoi anche usare la arrange()funzione plyrcome indicato da Hadley nel thread sopra:

library(plyr)
arrange(dd,desc(z),b)

Benchmark: nota che ho caricato ciascun pacchetto in una nuova sessione R poiché c'erano molti conflitti. In particolare, il caricamento del pacchetto doBy provoca la sortrestituzione di "I seguenti oggetti sono mascherati da 'x (posizione 17)': b, x, y, z" e il caricamento del pacchetto Deducer sovrascrive sort.data.frameda Kevin Wright o dal pacchetto taRifx.

#Load each time
dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"), 
      levels = c("Low", "Med", "Hi"), ordered = TRUE),
      x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
      z = c(1, 1, 1, 2))
library(microbenchmark)

# Reload R between benchmarks
microbenchmark(dd[with(dd, order(-z, b)), ] ,
    dd[order(-dd$z, dd$b),],
    times=1000
)

Tempi mediani:

dd[with(dd, order(-z, b)), ] 778

dd[order(-dd$z, dd$b),] 788

library(taRifx)
microbenchmark(sort(dd, f= ~-z+b ),times=1000)

Tempo medio: 1.567

library(plyr)
microbenchmark(arrange(dd,desc(z),b),times=1000)

Tempo medio: 862

library(doBy)
microbenchmark(orderBy(~-z+b, data=dd),times=1000)

Tempo medio: 1.694

Nota che doBy impiega un bel po 'di tempo per caricare il pacchetto.

library(Deducer)
microbenchmark(sortData(dd,c("z","b"),increasing= c(FALSE,TRUE)),times=1000)

Impossibile caricare Deducer. Necessita console JGR.

esort <- function(x, sortvar, ...) {
attach(x)
x <- x[with(x,order(sortvar,...)),]
return(x)
detach(x)
}

microbenchmark(esort(dd, -z, b),times=1000)

Non sembra essere compatibile con il microbenchmark a causa dell'attacco / distacco.


m <- microbenchmark(
  arrange(dd,desc(z),b),
  sort(dd, f= ~-z+b ),
  dd[with(dd, order(-z, b)), ] ,
  dd[order(-dd$z, dd$b),],
  times=1000
  )

uq <- function(x) { fivenum(x)[4]}  
lq <- function(x) { fivenum(x)[2]}

y_min <- 0 # min(by(m$time,m$expr,lq))
y_max <- max(by(m$time,m$expr,uq)) * 1.05

p <- ggplot(m,aes(x=expr,y=time)) + coord_cartesian(ylim = c( y_min , y_max )) 
p + stat_summary(fun.y=median,fun.ymin = lq, fun.ymax = uq, aes(fill=expr))

trama microbenchmark

(le linee si estendono dal quartile inferiore al quartile superiore, il punto è la mediana)


Dati questi risultati e soppesando la semplicità rispetto alla velocità, dovrei dare un cenno arrangenel plyrpacchetto . Ha una sintassi semplice e tuttavia è quasi veloce come la R base comanda con le loro macchinazioni contorte. Lavoro tipicamente geniale di Hadley Wickham. La mia unica lamentela è che rompe la nomenclatura R standard da cui vengono richiamati gli oggetti di ordinamento sort(object), ma capisco perché Hadley lo abbia fatto in questo modo a causa di problemi discussi nella domanda sopra collegata.


3
La funzione microbenchmark sopra ggplot2 è ora disponibile come taRifx::autoplot.microbenchmark.
Ari B. Friedman,

@ AriB.Friedman Quali sono gli intervalli dell'asse y / qual è la scala?
nought101

@ naught101 L'asse y inizia da 0. La scala dovrebbe essere microsecondi.
Ari B. Friedman,

2
@AME guarda come bè ordinato nell'esempio. L'impostazione predefinita è l'ordinamento in ordine crescente, quindi non lo avvolgi desc. Crescente in entrambi: arrange(dd,z,b). Scendendo in entrambi: arrange(dd,desc(z),desc(b)).
Ari B. Friedman,

2
Secondo ?arrange: "# NOTA: le funzioni plyr NON conservano row.names". Questo rende l'ottimale arrange()funzione non ottimale se si vuole mantenere row.names.
Landroni,

149

La risposta di Dirk è fantastica. Evidenzia anche una differenza chiave nella sintassi utilizzata per l'indicizzazione di data.frames e data.tables:

## The data.frame way
dd[with(dd, order(-z, b)), ]

## The data.table way: (7 fewer characters, but that's not the important bit)
dd[order(-z, b)]

La differenza tra le due chiamate è piccola, ma può avere conseguenze importanti. Soprattutto se scrivi codice di produzione e / o sei interessato alla correttezza nella tua ricerca, è meglio evitare la ripetizione non necessaria di nomi di variabili. data.table ti aiuta a fare questo.

Ecco un esempio di come la ripetizione dei nomi delle variabili potrebbe metterti nei guai:

Cambiamo il contesto dalla risposta di Dirk e diciamo che questo fa parte di un progetto più ampio in cui ci sono molti nomi di oggetti e sono lunghi e significativi; invece ddche si chiama quarterlyreport. Diventa :

quarterlyreport[with(quarterlyreport,order(-z,b)),]

Ok bene. Niente di sbagliato in questo. Successivamente il capo ti chiede di includere il rapporto dell'ultimo trimestre nel rapporto. Passi attraverso il tuo codice, aggiungendo un oggetto lastquarterlyreportin vari punti e in qualche modo (come mai?) Alla fine ottieni questo:

quarterlyreport[with(lastquarterlyreport,order(-z,b)),]

Non è quello che volevi dire ma non l'hai individuato perché l'hai fatto velocemente ed è incastonato in una pagina di codice simile. Il codice non cade (nessun avviso e nessun errore) perché R pensa che sia ciò che intendevi. Spereresti che chiunque legga il tuo rapporto lo rilevi, ma forse non lo fanno. Se lavori molto con i linguaggi di programmazione, questa situazione potrebbe essere tutta familiare. Era un "refuso" che dirai. Risolverò il "refuso" che dirai al tuo capo.

Nel data.tableci riguarda circa piccoli dettagli come questo. Quindi abbiamo fatto qualcosa di semplice per evitare di digitare due volte i nomi delle variabili. Qualcosa di molto semplice. iviene valutato nel quadro di ddgià, automaticamente. Non è necessario with()affatto.

Invece di

dd[with(dd, order(-z, b)), ]

è appena

dd[order(-z, b)]

E invece di

quarterlyreport[with(lastquarterlyreport,order(-z,b)),]

è appena

quarterlyreport[order(-z,b)]

È una differenza piccolissima, ma un giorno potrebbe semplicemente salvarti il ​​collo. Nel valutare le diverse risposte a questa domanda, considera di considerare le ripetizioni dei nomi delle variabili come uno dei tuoi criteri. Alcune risposte hanno alcune ripetizioni, altre no.


9
+1 Questo è un ottimo punto e arriva a un dettaglio della sintassi di R che mi ha spesso irritato. A volte uso subset()solo per evitare di dover fare ripetutamente riferimento allo stesso oggetto in una singola chiamata.
Josh O'Brien,

2
@ naught101 Data.table FAQ 1.9 risponde a questo?
Matt Dowle,

5
Suppongo che potresti aggiungere anche la nuova setorderfunzione qui, poiché questo thread è dove inviamo tutti i ordertipi dupes.
David Arenburg,

125

Ci sono molte risposte eccellenti qui, ma dplyr fornisce l'unica sintassi che posso ricordare rapidamente e facilmente (e quindi ora uso molto spesso):

library(dplyr)
# sort mtcars by mpg, ascending... use desc(mpg) for descending
arrange(mtcars, mpg)
# sort mtcars first by mpg, then by cyl, then by wt)
arrange(mtcars , mpg, cyl, wt)

Per il problema del PO:

arrange(dd, desc(z),  b)

    b x y z
1 Low C 9 2
2 Med D 3 1
3  Hi A 8 1
4  Hi A 9 1

2
La risposta accettata non funziona quando le mie colonne sono o tipo fattore (o qualcosa del genere) e voglio ordinare in modo decrescente per questa colonna fattore seguita da colonna intera in modo crescente. Ma funziona benissimo! Grazie!
Saheel Godhane,

10
Perché "solo"? Trovo che data.table sia dd[order(-z, b)]piuttosto facile da usare e da ricordare.
Matt Dowle,

2
D'accordo, non c'è molto tra questi due metodi ed data.tableè un enorme contributo anche Rin molti altri modi. Suppongo per me, potrebbe essere che avere un set di parentesi in meno (o un tipo in meno di parentesi) in questo caso riduca il carico cognitivo di una quantità appena percettibile.
Ben

7
Per me arrange()dipende dal fatto che è completamente dichiarativo, dd[order(-z, b)]non lo è.
Mullefa,

83

Il pacchetto R data.tablefornisce un ordinamento rapido ed efficiente della memoria di data.tables con una sintassi semplice (una parte di cui Matt ha evidenziato abbastanza bene nella sua risposta ). Ci sono stati molti miglioramenti e anche una nuova funzione setorder()da allora. Da v1.9.5+, setorder()funziona anche con data.frames .

Innanzitutto, creeremo un set di dati abbastanza grande e confronteremo i diversi metodi menzionati da altre risposte e quindi elencheremo le funzionalità di data.table .

Dati:

require(plyr)
require(doBy)
require(data.table)
require(dplyr)
require(taRifx)

set.seed(45L)
dat = data.frame(b = as.factor(sample(c("Hi", "Med", "Low"), 1e8, TRUE)),
                 x = sample(c("A", "D", "C"), 1e8, TRUE),
                 y = sample(100, 1e8, TRUE),
                 z = sample(5, 1e8, TRUE), 
                 stringsAsFactors = FALSE)

Punti di riferimenti:

I tempi riportati sono in esecuzione system.time(...)su queste funzioni mostrate di seguito. I tempi sono elencati di seguito (nell'ordine dal più lento al più veloce).

orderBy( ~ -z + b, data = dat)     ## doBy
plyr::arrange(dat, desc(z), b)     ## plyr
arrange(dat, desc(z), b)           ## dplyr
sort(dat, f = ~ -z + b)            ## taRifx
dat[with(dat, order(-z, b)), ]     ## base R

# convert to data.table, by reference
setDT(dat)

dat[order(-z, b)]                  ## data.table, base R like syntax
setorder(dat, -z, b)               ## data.table, using setorder()
                                   ## setorder() now also works with data.frames 

# R-session memory usage (BEFORE) = ~2GB (size of 'dat')
# ------------------------------------------------------------
# Package      function    Time (s)  Peak memory   Memory used
# ------------------------------------------------------------
# doBy          orderBy      409.7        6.7 GB        4.7 GB
# taRifx           sort      400.8        6.7 GB        4.7 GB
# plyr          arrange      318.8        5.6 GB        3.6 GB 
# base R          order      299.0        5.6 GB        3.6 GB
# dplyr         arrange       62.7        4.2 GB        2.2 GB
# ------------------------------------------------------------
# data.table      order        6.2        4.2 GB        2.2 GB
# data.table   setorder        4.5        2.4 GB        0.4 GB
# ------------------------------------------------------------
  • data.tableLa DT[order(...)]sintassi era ~ 10 volte più veloce del più veloce degli altri metodi ( dplyr), consumando la stessa quantità di memoria di dplyr.

  • data.tableÈ setorder()stato ~ 14 volte più veloce del più veloce degli altri metodi ( dplyr), pur prendendo solo 0,4 GB di memoria aggiuntiva . datè ora nell'ordine richiesto (poiché è aggiornato per riferimento).

caratteristiche di data.table:

Velocità:

  • L' ordinamento di data.table è estremamente veloce perché implementa l' ordinamento radix .

  • La sintassi DT[order(...)]è ottimizzata internamente per utilizzare anche l'ordinamento veloce di data.table . Puoi continuare a usare la familiare sintassi di base R ma velocizzare il processo (e usare meno memoria).

Memoria:

  • Il più delle volte, dopo il riordino non richiediamo l'originale data.frame o data.table . Cioè, di solito assegniamo il risultato allo stesso oggetto, ad esempio:

    DF <- DF[order(...)]

    Il problema è che ciò richiede almeno due volte (2x) la memoria dell'oggetto originale. Per essere efficiente in termini di memoria , data.table fornisce quindi anche una funzione setorder().

    setorder()riordina data.tables by reference ( sul posto ), senza effettuare ulteriori copie. Utilizza solo memoria aggiuntiva pari alla dimensione di una colonna.

Altre caratteristiche:

  1. Supporta integer, logical, numeric, charactere anche bit64::integer64i tipi.

    Si noti che factor, Date, POSIXctecc .. classi sono tutte integer/ numerici tipi sotto con attributi aggiuntivi e sono pertanto supportati.

  2. Nella base R, non possiamo usare -un vettore di caratteri per ordinare in base a quella colonna in ordine decrescente. Invece dobbiamo usare -xtfrm(.).

    Tuttavia, in data.table , possiamo semplicemente fare, per esempio, dat[order(-x)]o setorder(dat, -x).


Grazie per questa risposta molto istruttiva su data.table. Tuttavia, non capisco cos'è la "memoria di picco" e come l'hai calcolata. Potresti spiegare per favore? Grazie !
Julien Navarre,

Ho usato Strumenti -> allocazioni e riportato la dimensione "Tutte le macchine di heap e allocazione VM".
Arun,

2
@Arun il link Strumenti nel tuo commento è morto. Vuoi pubblicare un aggiornamento?
MichaelChirico,

@MichaelChirico Ecco un link alle informazioni sugli strumenti realizzati da Apple: developer.apple.com/library/content/documentation/…
n1k31t4


39

oppure puoi usare il pacchetto doBy

library(doBy)
dd <- orderBy(~-z+b, data=dd)

39

Supponi di avere un data.frame Ae desideri ordinarlo usando la colonna chiamata xordine decrescente. Chiama l'ordinatodata.frame newdata

newdata <- A[order(-A$x),]

Se vuoi un ordine crescente, sostituiscilo "-"con niente. Puoi avere qualcosa di simile

newdata <- A[order(-A$x, A$y, -A$z),]

dove xe zsono alcune colonne in data.frame A. Questo significa ordinare data.frame Ain ordine xdecrescente, ycrescente e zdecrescente.


32

se SQL ti viene naturale, il sqldfpacchetto gestisce ORDER BYcome previsto da Codd.


7
MJM, grazie per aver sottolineato questo pacchetto. È incredibilmente flessibile e poiché metà del mio lavoro è già fatto estraendo i database sql è più facile che apprendere gran parte della sintassi di R piuttosto che intuitiva.
Brandon Bertelsen,

31

In alternativa, usando il pacchetto Deducer

library(Deducer)
dd<- sortData(dd,c("z","b"),increasing= c(FALSE,TRUE))

19

In risposta a un commento aggiunto nel PO su come ordinare a livello di codice:

Utilizzando dplyredata.table

library(dplyr)
library(data.table)

dplyr

Basta usare arrange_, che è la versione di valutazione standard per arrange.

df1 <- tbl_df(iris)
#using strings or formula
arrange_(df1, c('Petal.Length', 'Petal.Width'))
arrange_(df1, ~Petal.Length, ~Petal.Width)
    Source: local data frame [150 x 5]

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
          (dbl)       (dbl)        (dbl)       (dbl)  (fctr)
1           4.6         3.6          1.0         0.2  setosa
2           4.3         3.0          1.1         0.1  setosa
3           5.8         4.0          1.2         0.2  setosa
4           5.0         3.2          1.2         0.2  setosa
5           4.7         3.2          1.3         0.2  setosa
6           5.4         3.9          1.3         0.4  setosa
7           5.5         3.5          1.3         0.2  setosa
8           4.4         3.0          1.3         0.2  setosa
9           5.0         3.5          1.3         0.3  setosa
10          4.5         2.3          1.3         0.3  setosa
..          ...         ...          ...         ...     ...


#Or using a variable
sortBy <- c('Petal.Length', 'Petal.Width')
arrange_(df1, .dots = sortBy)
    Source: local data frame [150 x 5]

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
          (dbl)       (dbl)        (dbl)       (dbl)  (fctr)
1           4.6         3.6          1.0         0.2  setosa
2           4.3         3.0          1.1         0.1  setosa
3           5.8         4.0          1.2         0.2  setosa
4           5.0         3.2          1.2         0.2  setosa
5           4.7         3.2          1.3         0.2  setosa
6           5.5         3.5          1.3         0.2  setosa
7           4.4         3.0          1.3         0.2  setosa
8           4.4         3.2          1.3         0.2  setosa
9           5.0         3.5          1.3         0.3  setosa
10          4.5         2.3          1.3         0.3  setosa
..          ...         ...          ...         ...     ...

#Doing the same operation except sorting Petal.Length in descending order
sortByDesc <- c('desc(Petal.Length)', 'Petal.Width')
arrange_(df1, .dots = sortByDesc)

maggiori informazioni qui: https://cran.r-project.org/web/packages/dplyr/vignettes/nse.html

È meglio usare la formula poiché cattura anche l'ambiente in cui valutare un'espressione

tabella dati

dt1 <- data.table(iris) #not really required, as you can work directly on your data.frame
sortBy <- c('Petal.Length', 'Petal.Width')
sortType <- c(-1, 1)
setorderv(dt1, sortBy, sortType)
dt1
     Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
  1:          7.7         2.6          6.9         2.3 virginica
  2:          7.7         2.8          6.7         2.0 virginica
  3:          7.7         3.8          6.7         2.2 virginica
  4:          7.6         3.0          6.6         2.1 virginica
  5:          7.9         3.8          6.4         2.0 virginica
 ---                                                            
146:          5.4         3.9          1.3         0.4    setosa
147:          5.8         4.0          1.2         0.2    setosa
148:          5.0         3.2          1.2         0.2    setosa
149:          4.3         3.0          1.1         0.1    setosa
150:          4.6         3.6          1.0         0.2    setosa

18

Ho imparato ordercon il seguente esempio che poi mi ha confuso a lungo:

set.seed(1234)

ID        = 1:10
Age       = round(rnorm(10, 50, 1))
diag      = c("Depression", "Bipolar")
Diagnosis = sample(diag, 10, replace=TRUE)

data = data.frame(ID, Age, Diagnosis)

databyAge = data[order(Age),]
databyAge

L'unico motivo per cui funziona questo esempio è perché orderè l'ordinamento per vector Age, non per la colonna denominata Agein data frame data.

Per vederlo, crea un frame di dati identico utilizzando read.tablenomi di colonna leggermente diversi e senza utilizzare nessuno dei vettori sopra elencati:

my.data <- read.table(text = '

  id age  diagnosis
   1  49 Depression
   2  50 Depression
   3  51 Depression
   4  48 Depression
   5  50 Depression
   6  51    Bipolar
   7  49    Bipolar
   8  49    Bipolar
   9  49    Bipolar
  10  49 Depression

', header = TRUE)

La struttura della linea sopra ordernon funziona più perché non esiste un vettore denominato age:

databyage = my.data[order(age),]

La seguente riga funziona perché orderordina sulla colonna agein my.data.

databyage = my.data[order(my.data$age),]

Ho pensato che valesse la pena pubblicare questo post, dato che ero così confuso da questo esempio per così tanto tempo. Se questo post non è ritenuto appropriato per la discussione, posso rimuoverlo.

EDIT: 13 maggio 2014

Di seguito è riportato un modo generalizzato di ordinare un frame di dati per ogni colonna senza specificare i nomi delle colonne. Il codice seguente mostra come ordinare da sinistra a destra o da destra a sinistra. Funziona se ogni colonna è numerica. Non ho provato con l'aggiunta di una colonna di caratteri.

Ho trovato il do.callcodice un mese o due fa in un vecchio post su un sito diverso, ma solo dopo una ricerca approfondita e difficile. Non sono sicuro di poter spostare quel post ora. Il thread attuale è il primo colpo per ordinare un data.framein R. Quindi, ho pensato che la mia versione estesa di quel do.callcodice originale potesse essere utile.

set.seed(1234)

v1  <- c(0,0,0,0, 0,0,0,0, 1,1,1,1, 1,1,1,1)
v2  <- c(0,0,0,0, 1,1,1,1, 0,0,0,0, 1,1,1,1)
v3  <- c(0,0,1,1, 0,0,1,1, 0,0,1,1, 0,0,1,1)
v4  <- c(0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1)

df.1 <- data.frame(v1, v2, v3, v4) 
df.1

rdf.1 <- df.1[sample(nrow(df.1), nrow(df.1), replace = FALSE),]
rdf.1

order.rdf.1 <- rdf.1[do.call(order, as.list(rdf.1)),]
order.rdf.1

order.rdf.2 <- rdf.1[do.call(order, rev(as.list(rdf.1))),]
order.rdf.2

rdf.3 <- data.frame(rdf.1$v2, rdf.1$v4, rdf.1$v3, rdf.1$v1) 
rdf.3

order.rdf.3 <- rdf.1[do.call(order, as.list(rdf.3)),]
order.rdf.3

4
Tale sintassi funziona se si memorizzano i dati in un file data.table, anziché in un data.frame: require(data.table); my.dt <- data.table(my.data); my.dt[order(age)]funziona perché i nomi delle colonne sono resi disponibili tra parentesi [].
Frank,

Non penso che il downvote sia necessario qui, ma nemmeno penso che ciò aggiunga molto alla domanda attuale, in particolare considerando il set di risposte esistente, alcune delle quali già catturano il requisito con data.frames per usare witho $.
A5C1D2H2I1M1N2O1R2T1

1
l'upgrade per do.callquesto semplifica l' ordinamento di un frame di dati a più colonne. Si do.call(sort, mydf.obj)avrà semplicemente una bellissima cascata.
AdamO,

17

La risposta di Dirk è buona, ma se hai bisogno che l'ordinamento persista, ti consigliamo di applicare nuovamente l'ordinamento al nome di quel frame di dati. Utilizzando il codice di esempio:

dd <- dd[with(dd, order(-z, b)), ] 

13

Il arrangiamento () in dplyer è la mia opzione preferita. Utilizzare l'operatore del tubo e passare dall'aspetto meno importante a quello più importante

dd1 <- dd %>%
    arrange(z) %>%
    arrange(desc(x))

7

Solo per completezza, dal momento che non è stato detto molto sull'ordinamento per numero di colonna ... Si può sicuramente affermare che spesso non è desiderabile (perché l'ordine delle colonne potrebbe cambiare, aprendo la strada agli errori), ma in alcune situazioni specifiche (quando ad esempio hai bisogno di un lavoro veloce e non c'è il rischio che le colonne cambino gli ordini), potrebbe essere la cosa più sensata da fare, specialmente quando si tratta di un gran numero di colonne.

In tal caso, do.call()viene in soccorso:

ind <- do.call(what = "order", args = iris[,c(5,1,2,3)])
iris[ind, ]

##        Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
##    14           4.3         3.0          1.1         0.1     setosa
##    9            4.4         2.9          1.4         0.2     setosa
##    39           4.4         3.0          1.3         0.2     setosa
##    43           4.4         3.2          1.3         0.2     setosa
##    42           4.5         2.3          1.3         0.3     setosa
##    4            4.6         3.1          1.5         0.2     setosa
##    48           4.6         3.2          1.4         0.2     setosa
##    7            4.6         3.4          1.4         0.3     setosa
##    (...)

6

Per completezza: puoi anche usare la sortByCol()funzione dal BBmiscpacchetto:

library(BBmisc)
sortByCol(dd, c("z", "b"), asc = c(FALSE, TRUE))
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1

Confronto delle prestazioni:

library(microbenchmark)
microbenchmark(sortByCol(dd, c("z", "b"), asc = c(FALSE, TRUE)), times = 100000)
median 202.878

library(plyr)
microbenchmark(arrange(dd,desc(z),b),times=100000)
median 148.758

microbenchmark(dd[with(dd, order(-z, b)), ], times = 100000)
median 115.872

4
strano aggiungere un confronto delle prestazioni quando il tuo metodo è il più lento ... in ogni caso dubita del valore dell'uso di un benchmark su 4 filedata.frame
MichaelChirico

5

Proprio come i selezionatori di carte meccanici di molto tempo fa, prima ordina per la chiave meno significativa, poi la successiva più significativa, ecc. Nessuna libreria richiesta, funziona con qualsiasi numero di chiavi e qualsiasi combinazione di chiavi ascendenti e discendenti.

 dd <- dd[order(dd$b, decreasing = FALSE),]

Ora siamo pronti a fare la chiave più significativa. L'ordinamento è stabile e tutti i legami nella chiave più significativa sono già stati risolti.

dd <- dd[order(dd$z, decreasing = TRUE),]

Questo potrebbe non essere il più veloce, ma è certamente semplice e affidabile


4

Un'altra alternativa, utilizzando il rgrpacchetto:

> library(rgr)
> gx.sort.df(dd, ~ -z+b)
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1

4

Ero alle prese con le soluzioni di cui sopra quando volevo automatizzare il mio processo di ordinazione per n colonne, i cui nomi di colonna potevano essere ogni volta diversi. Ho trovato una funzione super utile dal psychpacchetto per farlo in modo semplice:

dfOrder(myDf, columnIndices)

dove columnIndicessono gli indici di una o più colonne, nell'ordine in cui si desidera ordinare. Maggiori informazioni qui:

dfOrder funzione dal pacchetto 'psych'

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.