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)).

Illustration der Programmiersprachen bei Coddy

Lerne mit Coddy zu programmieren

Los geht's