Menu

Sortieren in R: sort(), order() und arrange()

Wie Sortieren in R wirklich funktioniert: sort() für Vektoren, warum Data Frames den Index-Trick von order() brauchen, absteigende und mehrspaltige Sortierungen und dplyr's arrange().

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

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 = TRUE dreht um; NAs werden verworfen, außer mit na.last = TRUE.
  • order(x) gibt Positionen zurück, und df[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ür order().
  • 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)).

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S