Menu

Ordinamento in R: sort(), order() e arrange()

Come funziona davvero l'ordinamento in R: sort() per i vettori, perché i data frame hanno bisogno del trucco degli indici di order(), l'ordine decrescente e su più colonne, e arrange() di dplyr.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

sort() ordina i valori di un vettore

Per un semplice vettore, sort() fa esattamente quello che ti aspetti: restituisce i valori in ordine crescente (l'originale resta intatto):

Due opzioni da conoscere. decreasing = TRUE inverte la direzione. E di default sort() scarta in silenzio i valori NA: sort(c(3, NA, 1)) restituisce solo 1 3. Se i valori mancanti devono sopravvivere all'ordinamento, di' dove metterli: sort(x, na.last = TRUE) li conserva, dopo i valori ordinati.

Fin qui, tutto ovvio. La parte interessante è capire perché sort() è lo strumento sbagliato per i data frame.

order() restituisce posizioni: il cambio di prospettiva

sort() risponde a "quali sono i valori, in ordine?". order() risponde a una domanda diversa: "quali posizioni dovrei visitare per vedere i valori in ordine?"

Leggi order(times) come un'istruzione: il valore più piccolo sta in posizione 2, il successivo in posizione 4, poi 1, poi 3. Indicizzando con queste istruzioni, times[order(times)], riproduci esattamente sort(times).

Perché è importante? Perché una riga di un data frame è una squadra di valori che devono muoversi insieme. Ordinare da sola la colonna time con sort() riordinerebbe una colonna lasciando indietro le compagne: ogni riga mescolata. order() invece ti dà le posizioni delle righe, e mettendo le posizioni nello spazio delle righe tra le parentesi quadre sposti righe intere:

Il 9.8 di Ben arriva con il nome di Ben ancora attaccato. È tutto qui il trucco, ed è *l'*idioma per ordinare i data frame in R base: df[order(df$column), ]. (Le etichette di riga stampate, 2 4 1 3, sono i numeri di riga originali che si portano dietro; innocue.)

Ordine decrescente e su più colonne

Per un ordinamento numerico decrescente, nega la colonna: ordinare -time in modo crescente equivale a ordinare time in modo decrescente. E order() accetta più colonne, prima le prime e poi le successive per risolvere i pareggi:

La seconda chiamata ordina i reparti in ordine alfabetico e, dentro ogni reparto, gli stipendi dal più alto al più basso. Il trucco della negazione funziona solo con i numeri: -df$name su una colonna di caratteri è un errore. Per il testo in ordine decrescente usa invece order(df$name, decreasing = TRUE) (che inverte tutte le chiavi di ordinamento insieme).

rank() è il terzo fratello

Di passaggio: rank(x) risponde a un'altra domanda ancora, "che posto occupa ogni valore?", senza spostare niente:

sort() dà i valori ordinati, order() dà le posizioni da visitare, rank() dà la posizione in classifica di ogni valore, lasciandolo dov'è. Si confondono continuamente order() e rank(); nota che sono permutazioni inverse l'una dell'altra, e usa rank() solo quando vuoi davvero delle posizioni in classifica (classifiche, percentili).

Il modo dplyr: arrange()

arrange() di dplyr racchiude tutta la danza di order() in un verbo: le colonne sono le chiavi di ordinamento e desc() ne inverte una (codice statico: la sandbox esegue solo R base):

library(dplyr)

runners |> arrange(time)
staff   |> arrange(dept, desc(salary))

Niente parentesi quadre, niente $, niente trucco della negazione: desc() funziona anche sulle colonne di caratteri. Una differenza di comportamento da conoscere: arrange() mette i valori NA in fondo qualunque sia la direzione, mentre order() di base usa anch'esso na.last = TRUE come default. Vedi l'introduzione a dplyr per come arrange() si concatena con filter() e compagnia.

L'ordinamento dei caratteri ha i suoi spigoli

Due avvertenze quando ordini del testo. Primo, le cifre salvate come testo si ordinano come testo: il confronto tra caratteri procede simbolo per simbolo:

"10" viene prima di "2" perché il confronto si ferma al primo simbolo: "1" < "2". Se una colonna di numeri si ordina in modo strano, quasi sicuramente è salvata come carattere: convertila prima con as.numeric() (una conseguenza frequente di un'importazione CSV disordinata).

Secondo, l'ordine del testo dipende dal locale del sistema: accenti, maiuscole e alfabeti non latini possono ordinarsi in modo diverso sul tuo portatile rispetto a un server con locale C. Un output ordinato che deve essere identico su macchine diverse dovrebbe impostare il locale in modo esplicito oppure ordinare una chiave normalizzata.

Cosa ti porti a casa

  • sort(x) ordina i valori di un vettore; decreasing = TRUE inverte l'ordine; gli NA vengono scartati a meno di na.last = TRUE.
  • order(x) restituisce posizioni, e df[order(df$x), ] è *l'*idioma di base per ordinare i data frame.
  • Su più colonne: order(df$a, -df$b); la negazione per l'ordine decrescente funziona solo con i numeri.
  • rank() dà le posizioni in classifica senza riordinare: non sostituisce order().
  • arrange(dept, desc(salary)) di dplyr è lo stesso ordinamento con meno punteggiatura.
  • Nel testo "10" viene prima di "2": controlla i tipi delle tue colonne.

Prossimo passo: riassumere le righe per gruppi con table(), tapply(), aggregate() e group_by() di dplyr.

Domande frequenti

Come si ordina un data frame per una colonna in R?

Usa order() dentro le parentesi quadre delle righe: df[order(df$price), ]. order() restituisce le posizioni delle righe nell'ordine giusto, e indicizzando con esse riorganizzi l'intero data frame. sort() qui non funziona: ordina i valori di un solo vettore, perdendo il loro legame con le altre colonne.

Qual è la differenza tra sort() e order() in R?

sort(x) restituisce i valori di x riordinati. order(x) restituisce le posizioni (gli indici) che metterebbero x in ordine, ed è ciò che ti serve per ordinare un intero data frame in base a una sua colonna: df[order(df$x), ].

Come si ordina in modo decrescente in R?

Per un vettore: sort(x, decreasing = TRUE). Per un data frame: df[order(-df$x), ] (neghi una colonna numerica) oppure df[order(df$x, decreasing = TRUE), ], che funziona anche con le colonne di caratteri, dove la negazione non si può usare. In dplyr: arrange(df, desc(x)).

Come si ordina per più colonne in R?

Passale tutte a order(): df[order(df$dept, -df$salary), ] ordina per reparto e poi, dentro ogni reparto, per stipendio decrescente. I primi argomenti sono le chiavi principali; quelli successivi risolvono i pareggi. In dplyr: arrange(df, dept, desc(salary)).

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA