sort() sortiert die Werte eines Vektors
Für einen einfachen Vektor tut sort() genau das, was man erwartet - es gibt die Werte in aufsteigender Reihenfolge zurück (das Original bleibt unberührt):
Zwei Optionen lohnt es zu kennen. decreasing = TRUE dreht die Richtung um. Und sort() verwirft NA-Werte standardmäßig stillschweigend - sort(c(3, NA, 1)) gibt nur 1 3 zurück. Sollen fehlende Werte die Sortierung überleben, muss man sagen, wohin sie gehören: sort(x, na.last = TRUE) behält sie, platziert nach den geordneten Werten.
So weit, so offensichtlich. Der interessante Teil ist, warum sort() das falsche Werkzeug für Data Frames ist.
order() gibt Positionen zurück - der Perspektivwechsel
sort() beantwortet "Was sind die Werte, in Reihenfolge?" order() beantwortet eine andere Frage: "Welche Positionen müsste ich abklappern, um die Werte in Reihenfolge zu sehen?"
Lies order(times) als Anleitung: Der kleinste Wert sitzt an Position 2, der nächste an Position 4, dann 1, dann 3. Indexiert man mit dieser Anleitung - times[order(times)] -, reproduziert das exakt sort(times).
Warum ist das wichtig? Weil eine Data-Frame-Zeile ein Team von Werten ist, das sich gemeinsam bewegen muss. Die time-Spalte allein mit sort() zu sortieren würde eine Spalte umordnen und ihre Teamkollegen zurücklassen - jede Zeile durcheinander. order() liefert stattdessen Zeilenpositionen, und Positionen im Zeilen-Slot der Klammern bewegen ganze Zeilen:
Bens 9.8 kommt mit Bens Namen noch dran an. Das ist der ganze Trick, und es ist das Idiom zum Sortieren von Data Frames in Base R: df[order(df$spalte), ]. (Die ausgegebenen Zeilenlabels - 2 4 1 3 - sind die mitreisenden ursprünglichen Zeilennummern; harmlos.)
Absteigende und mehrspaltige Sortierungen
Für absteigende numerische Sortierungen die Spalte negieren - -time aufsteigend zu ordnen heißt, time absteigend zu ordnen. Und order() nimmt mehrere Spalten, frühere zuerst, spätere lösen Gleichstände auf:
Der zweite Aufruf sortiert Abteilungen alphabetisch und innerhalb jeder Abteilung die Gehälter von hoch nach niedrig. Der Negationstrick funktioniert nur bei Zahlen - -df$name auf einer Zeichenspalte ist ein Fehler. Für absteigenden Text stattdessen order(df$name, decreasing = TRUE) verwenden (das dreht alle Sortierschlüssel auf einmal um).
rank() ist das dritte Geschwister
Nebenbei: rank(x) beantwortet noch eine andere Frage - "Welchen Platz belegt jeder Wert?" -, ohne irgendetwas zu bewegen:
sort() liefert geordnete Werte, order() liefert zu besuchende Positionen, rank() liefert die Platzierung jedes Werts an Ort und Stelle. order() und rank() werden ständig verwechselt; beachte, dass sie zueinander inverse Permutationen sind, und greif nur dann zu rank(), wenn du buchstäblich Platzierungen willst (Bestenlisten, Perzentile).
Der dplyr-Weg: arrange()
dplyr's arrange() verpackt den ganzen order()-Tanz in ein Verb - Spalten sind Sortierschlüssel, desc() dreht eine um (statisch; die Sandbox führt nur Base R aus):
library(dplyr)
runners |> arrange(time)
staff |> arrange(dept, desc(salary))
Keine Klammern, kein $, kein Negationstrick - desc() funktioniert auch auf Zeichenspalten. Ein Verhaltensunterschied lohnt das Wissen: arrange() platziert NA-Werte unabhängig von der Richtung am Ende, während Base order() ebenfalls standardmäßig na.last = TRUE verwendet. Siehe die dplyr-Einführung dazu, wie sich arrange() mit filter() und Co. verkettet.
Textsortierung hat scharfe Kanten
Zwei Vorbehalte beim Sortieren von Text. Erstens sortieren als Text gespeicherte Ziffern als Text - der Zeichenvergleich geht Symbol für Symbol:
"10" sortiert vor "2", weil der Vergleich beim ersten Symbol endet: "1" < "2". Wenn eine Zahlenspalte seltsam sortiert, ist sie mit ziemlicher Sicherheit als Zeichenkette gespeichert - erst mit as.numeric() konvertieren (eine häufige Nachwirkung eines unsauberen CSV-Imports).
Zweitens hängt die Textreihenfolge vom Locale deines Systems ab - Akzente, Groß-/Kleinschreibung und nicht-lateinische Schriften können auf deinem Laptop anders sortieren als auf einem Server mit C-Locale. Sortierte Ausgaben, die maschinenübergreifend identisch sein müssen, sollten entweder das Locale explizit setzen oder einen normalisierten Schlüssel sortieren.
Was du mitnimmst
sort(x)ordnet die Werte eines Vektors;decreasing = TRUEdreht um;NAs werden verworfen, außer mitna.last = TRUE.order(x)gibt Positionen zurück, unddf[order(df$x), ]ist das Base-Idiom zum Sortieren von Data Frames.- Mehrspaltig:
order(df$a, -df$b); Negation für absteigend funktioniert nur bei Zahlen. rank()liefert Platzierungen ohne Umordnen - kein Ersatz fürorder().- dplyr's
arrange(dept, desc(salary))ist dieselbe Sortierung mit weniger Interpunktion. "10"sortiert im Text vor"2"- prüfe deine Spaltentypen.
Als Nächstes: Zeilen zu Gruppenzusammenfassungen verdichten mit table(), tapply(), aggregate() und dplyr's group_by().
Häufig gestellte Fragen
Wie sortiere ich einen Data Frame nach einer Spalte in R?
Verwende order() innerhalb der Zeilenklammern: df[order(df$price), ]. order() gibt die Zeilenpositionen in sortierter Reihenfolge zurück, und die Indexierung damit ordnet den gesamten Data Frame um. sort() funktioniert hier nicht - es sortiert die Werte eines einzelnen Vektors und verliert deren Verbindung zu den anderen Spalten.
Was ist der Unterschied zwischen sort() und order() in R?
sort(x) gibt die Werte von x in sortierter Reihenfolge zurück. order(x) gibt die Positionen (Indizes) zurück, die x in Ordnung bringen würden - genau das, was man braucht, um einen ganzen Data Frame nach einer seiner Spalten zu sortieren: df[order(df$x), ].
Wie sortiere ich in R absteigend?
Für einen Vektor: sort(x, decreasing = TRUE). Für einen Data Frame: df[order(-df$x), ] (eine numerische Spalte negieren) oder df[order(df$x, decreasing = TRUE), ], was auch bei Zeichenspalten funktioniert, wo Negation nicht geht. In dplyr: arrange(df, desc(x)).
Wie sortiere ich nach mehreren Spalten in R?
Alle an order() übergeben: df[order(df$dept, -df$salary), ] sortiert nach Abteilung und innerhalb jeder Abteilung nach Gehalt, absteigend. Frühere Argumente sind die primären Schlüssel; spätere lösen Gleichstände auf. In dplyr: arrange(df, dept, desc(salary)).