Ich möchte einen data.frame nach mehreren Spalten sortieren. Zum Beispiel möchte ich mit dem Datenrahmen unten nach Spalte z
(absteigend) und dann nach Spalte b
(aufsteigend) sortieren :
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
with
. Versuchen SieM <- matrix(c(1,2,2,2,3,6,4,5), 4, 2, byrow=FALSE, dimnames=list(NULL, c("a","b")))
, eine Matrix zu erstellenM
, undM[order(M[,"a"],-M[,"b"]),]
ordnen Sie sie dann in zwei Spalten an.dd[ order(-dd[,4], dd[,1]), ]
kann aber nichtwith
für namenbasierte Teilmengen verwendet werden.xtfrm
, zum Beispieldd[ order(-xtfrm(dd[,4]), dd[,1]), ]
.Deine Entscheidungen
order
vonbase
arrange
vondplyr
setorder
undsetorderv
vondata.table
arrange
vonplyr
sort
vontaRifx
orderBy
vondoBy
sortData
vonDeducer
In den meisten Fällen sollten Sie die
dplyr
oderdata.table
-Lösungen verwenden, es sei denn, es ist wichtig, keine Abhängigkeiten zu haben. In diesem Fall sollten Sie sie verwendenbase::order
.Ich habe kürzlich sort.data.frame zu einem CRAN-Paket hinzugefügt, um es klassenkompatibel zu machen, wie hier beschrieben: Beste Methode zum Erstellen einer generischen / Methodenkonsistenz für sort.data.frame?
Daher können Sie angesichts des data.frame dd wie folgt sortieren:
Wenn Sie einer der ursprünglichen Autoren dieser Funktion sind, kontaktieren Sie mich bitte. Die Diskussion über Public Domaininess finden Sie hier: http://chat.stackoverflow.com/transcript/message/1094290#1094290
Sie können auch die
arrange()
Funktion von verwenden,plyr
wie Hadley im obigen Thread ausgeführt hat:Benchmarks: Beachten Sie, dass ich jedes Paket in eine neue R-Sitzung geladen habe, da es viele Konflikte gab. Insbesondere das Laden des doBy-Pakets führt
sort
dazu, dass "Die folgenden Objekte werden von 'x (Position 17)' maskiert: b, x, y, z" zurückgegeben wird und das Laden des Deducer-Paketssort.data.frame
von Kevin Wright oder dem taRifx-Paket überschrieben wird .Medianzeiten:
dd[with(dd, order(-z, b)), ]
778dd[order(-dd$z, dd$b),]
788Medianzeit: 1.567
Medianzeit: 862
Medianzeit: 1.694
Beachten Sie, dass doBy einige Zeit zum Laden des Pakets benötigt.
Deducer konnte nicht geladen werden. Benötigt JGR-Konsole.
Scheint aufgrund des Anbringens / Entfernens nicht mit Microbenchmark kompatibel zu sein.
(Linien erstrecken sich vom unteren zum oberen Quartil, Punkt ist der Median)
Angesichts dieser Ergebnisse und der Abwägung von Einfachheit und Geschwindigkeit müsste ich
arrange
demplyr
Paket zustimmen . Es hat eine einfache Syntax und ist dennoch fast so schnell wie die Basis-R-Befehle mit ihren verschlungenen Machenschaften. Typisch brillante Hadley Wickham Arbeit. Mein einziger Kritikpunkt ist, dass es die Standard-R-Nomenklatur bricht, nach der Sortierobjekte aufgerufen werdensort(object)
, aber ich verstehe, warum Hadley dies aufgrund von Problemen getan hat, die in der oben verlinkten Frage erörtert wurden.quelle
taRifx::autoplot.microbenchmark
.b
im Beispiel sortiert ist. Die Standardeinstellung ist Sortieren nach aufsteigend, sodass Sie sie einfach nicht einpackendesc
. In beiden aufsteigend :arrange(dd,z,b)
. Absteigend in beiden :arrange(dd,desc(z),desc(b))
.?arrange
: "# HINWEIS: plyr Funktionen erhalten kein row.names". Dies macht die hervorragendearrange()
Funktion suboptimal, wenn man sie behalten willrow.names
.Dirks Antwort ist großartig. Es wird auch ein wesentlicher Unterschied in der Syntax für die Indizierung von
data.frame
s unddata.table
s hervorgehoben:Der Unterschied zwischen den beiden Anrufen ist gering, kann jedoch wichtige Konsequenzen haben. Insbesondere wenn Sie Produktionscode schreiben und / oder bei Ihrer Recherche auf Korrektheit achten, ist es am besten, unnötige Wiederholungen von Variablennamen zu vermeiden.
data.table
hilft Ihnen dabei.Hier ist ein Beispiel dafür, wie die Wiederholung von Variablennamen zu Problemen führen kann:
Lassen Sie uns den Kontext von Dirks Antwort ändern und sagen, dass dies Teil eines größeren Projekts ist, bei dem es viele Objektnamen gibt und diese lang und aussagekräftig sind. statt
dd
heißt esquarterlyreport
. Es wird :Ok, gut. Daran ist nichts auszusetzen. Als nächstes bittet Sie Ihr Chef, den Bericht des letzten Quartals in den Bericht aufzunehmen. Sie gehen Ihren Code durch, fügen an
lastquarterlyreport
verschiedenen Stellen ein Objekt hinzu und erhalten (wie um alles in der Welt?) Am Ende Folgendes:Das haben Sie nicht gemeint, aber Sie haben es nicht erkannt, weil Sie es schnell gemacht haben und es sich auf einer Seite mit ähnlichem Code befindet. Der Code fällt nicht um (keine Warnung und kein Fehler), weil R denkt, dass es das ist, was Sie gemeint haben. Sie würden hoffen, dass jeder, der Ihren Bericht liest, ihn entdeckt, aber vielleicht nicht. Wenn Sie viel mit Programmiersprachen arbeiten, ist diese Situation möglicherweise allzu vertraut. Es war ein "Tippfehler", den Sie sagen werden. Ich werde den "Tippfehler" beheben, den Sie Ihrem Chef sagen werden.
In sind
data.table
wir besorgt über winzige Details wie dieses. Wir haben also etwas Einfaches getan, um zu vermeiden, dass Variablennamen zweimal eingegeben werden. Etwas sehr Einfaches.i
wird im Rahmen vondd
bereits automatisch ausgewertet . Du brauchst überhaupt nichtwith()
.Anstatt
es ist nur
Und statt
es ist nur
Es ist ein sehr kleiner Unterschied, aber es könnte eines Tages Ihren Hals retten. Berücksichtigen Sie beim Abwägen der verschiedenen Antworten auf diese Frage die Wiederholungen von Variablennamen als eines Ihrer Entscheidungskriterien. Einige Antworten haben einige Wiederholungen, andere keine.
quelle
subset()
nur, um zu vermeiden, dass ich innerhalb eines einzelnen Aufrufs wiederholt auf dasselbe Objekt verweisen muss.setorder
Funktion auch hier hinzufügen , da wir in diesem Thread alleorder
Typ-Dupes senden .Hier gibt es viele hervorragende Antworten, aber dplyr gibt die einzige Syntax an, an die ich mich schnell und einfach erinnern kann (und die ich jetzt sehr oft verwende):
Für das Problem des OP:
quelle
dd[order(-z, b)]
ziemlich einfach zu bedienen und erinnere mich.data.table
ist auchR
in vielerlei Hinsicht ein großer Beitrag dazu . Ich nehme an, es könnte sein, dass ein Satz weniger Klammern (oder ein Klammertyp weniger) in diesem Fall die kognitive Belastung um einen kaum wahrnehmbaren Betrag verringert.arrange()
das völlig deklarativdd[order(-z, b)]
ist, nicht.Das R-Paket
data.table
bietet sowohl eine schnelle als auch speichereffiziente Bestellung von data.tables mit einer einfachen Syntax (ein Teil davon hat Matt in seiner Antwort sehr gut hervorgehoben ). Es gab viele Verbesserungen und auch eine neue Funktionsetorder()
. Vonv1.9.5+
,setorder()
arbeitet auch mit data.frames .Zuerst erstellen wir einen Datensatz, der groß genug ist, und vergleichen die verschiedenen Methoden, die aus anderen Antworten hervorgehen, und listen dann die Funktionen von data.table auf .
Daten:
Benchmarks:
Die angegebenen Timings stammen aus den
system.time(...)
unten gezeigten Funktionen. Die Zeiten sind unten tabellarisch aufgeführt (in der Reihenfolge der langsamsten bis schnellsten).data.table
DieDT[order(...)]
Syntax war ~ 10x schneller als die schnellste aller anderen Methoden (dplyr
), während die gleiche Speichermenge verbraucht wurde wiedplyr
.data.table
‚ssetorder()
war ~ 14x schneller als die schnellste von anderen Methoden (dplyr
), während der Einnahme von nur 0.4GB zusätzlichem Speicher .dat
ist jetzt in der Reihenfolge, die wir benötigen (da es durch Bezugnahme aktualisiert wird).data.table Funktionen:
Geschwindigkeit:
Die Bestellung von data.table ist extrem schnell, da sie die Radix-Reihenfolge implementiert .
Die Syntax
DT[order(...)]
ist intern optimiert, um auch die schnelle Bestellung von data.table zu nutzen . Sie können weiterhin die bekannte Basis-R-Syntax verwenden, aber den Prozess beschleunigen (und weniger Speicher verwenden).Erinnerung:
In den meisten Fällen benötigen wir nach der Neuordnung weder den ursprünglichen data.frame noch die data.table . Das heißt, wir weisen das Ergebnis normalerweise demselben Objekt zu, zum Beispiel:
Das Problem ist, dass dies mindestens das Doppelte (2x) des Speichers des ursprünglichen Objekts erfordert. Um speichereffizient zu sein , bietet data.table daher auch eine Funktion
setorder()
.setorder()
ordnet data.tablesby reference
( an Ort und Stelle ) neu an, ohne zusätzliche Kopien anzufertigen . Es wird nur zusätzlicher Speicher verwendet, der der Größe einer Spalte entspricht.Andere Eigenschaften:
Es unterstützt
integer
,logical
,numeric
,character
und sogarbit64::integer64
Typen.In Basis R können wir nicht verwenden
-
Zeichenvektor verwenden, um nach dieser Spalte in absteigender Reihenfolge zu sortieren. Stattdessen müssen wir verwenden-xtfrm(.)
.In data.table können wir dies jedoch beispielsweise
dat[order(-x)]
oder tunsetorder(dat, -x)
.quelle
Mit dieser (sehr hilfreichen) Funktion von Kevin Wright , die im Abschnitt "Tipps" des R-Wikis veröffentlicht wurde, ist dies leicht zu erreichen.
quelle
oder Sie können das Paket doBy verwenden
quelle
Angenommen, Sie haben eine
data.frame
A
und möchten diese nach einer Spalte sortieren, die alsx
absteigende Reihenfolge bezeichnet wird. Rufen Sie die sortiertedata.frame
newdata
Wenn Sie eine aufsteigende Reihenfolge wünschen, ersetzen Sie diese
"-"
durch nichts. Sie können so etwas habenwo
x
undz
sind einige Spalten indata.frame
A
. Dies bedeutet Sortierendata.frame
A
nachx
absteigend,y
aufsteigend undz
absteigend.quelle
Wenn SQL für Sie selbstverständlich ist, wird das
sqldf
PaketORDER BY
wie von Codd beabsichtigt behandelt.quelle
Alternativ können Sie das Paket Deducer verwenden
quelle
Als Antwort auf einen im OP hinzugefügten Kommentar zum programmgesteuerten Sortieren:
Verwenden von
dplyr
unddata.table
dplyr
Verwenden Sie einfach
arrange_
die Standard-Evaluierungsversion fürarrange
.Weitere Informationen hier: https://cran.r-project.org/web/packages/dplyr/vignettes/nse.html
Es ist besser, eine Formel zu verwenden, da sie auch die Umgebung erfasst, in der ein Ausdruck ausgewertet wird
Datentabelle
quelle
Ich habe
order
mit folgendem Beispiel davon erfahren, was mich dann lange verwirrt hat:Der einzige Grund, warum dieses Beispiel funktioniert, ist die
order
Sortierung nach dervector Age
und nicht nach derAge
in der Spalte genannten Spaltedata frame data
.Um dies zu sehen, erstellen Sie einen identischen Datenrahmen
read.table
mit leicht unterschiedlichen Spaltennamen und ohne Verwendung eines der oben genannten Vektoren:Die obige Linienstruktur
order
funktioniert nicht mehr, da kein Vektor mit dem Namenage
:Die folgende Zeile funktioniert, weil
order
die Spalteage
in sortiert wirdmy.data
.Ich dachte, das wäre es wert, veröffentlicht zu werden, da ich so lange von diesem Beispiel verwirrt war. Wenn dieser Beitrag für den Thread nicht geeignet ist, kann ich ihn entfernen.
EDIT: 13. Mai 2014
Im Folgenden finden Sie eine allgemeine Methode zum Sortieren eines Datenrahmens nach jeder Spalte, ohne Spaltennamen anzugeben. Der folgende Code zeigt, wie von links nach rechts oder von rechts nach links sortiert wird. Dies funktioniert, wenn jede Spalte numerisch ist. Ich habe es nicht mit einer hinzugefügten Zeichenspalte versucht.
Ich habe den
do.call
Code vor ein oder zwei Monaten in einem alten Beitrag auf einer anderen Site gefunden, aber erst nach umfangreicher und schwieriger Suche. Ich bin mir nicht sicher, ob ich diesen Beitrag jetzt verschieben könnte. Der vorliegende Thread ist der erste Treffer für die Bestellung einesdata.frame
InR
. Daher dachte ich, meine erweiterte Version dieses Originalcodesdo.call
könnte nützlich sein.quelle
require(data.table); my.dt <- data.table(my.data); my.dt[order(age)]
Dies funktioniert, weil die Spaltennamen in den Klammern [] verfügbar gemacht werden.data.frame
s erfassen , entwederwith
oder zu verwenden$
.do.call
einen mehrspaltigen Datenrahmen in kurzer Zeit sortieren. Einfachdo.call(sort, mydf.obj)
und eine schöne Kaskadensorte wird man haben.Dirks Antwort ist gut, aber wenn Sie die Sortierung beibehalten möchten, möchten Sie die Sortierung wieder auf den Namen dieses Datenrahmens anwenden. Verwenden Sie den Beispielcode:
quelle
Das arrangieren () in dplyer ist meine Lieblingsoption. Verwenden Sie den Rohrbetreiber und wechseln Sie vom am wenigsten wichtigen zum wichtigsten Aspekt
quelle
Nur der Vollständigkeit halber, da nicht viel über das Sortieren nach Spaltennummern gesagt wurde ... Es kann sicherlich argumentiert werden, dass dies oft nicht wünschenswert ist (weil sich die Reihenfolge der Spalten ändern könnte, was den Weg zu Fehlern ebnet), aber In bestimmten Situationen (wenn Sie beispielsweise eine schnelle Arbeit erledigen müssen und kein derartiges Risiko besteht, dass Spalten die Reihenfolge ändern) ist dies möglicherweise am sinnvollsten, insbesondere wenn Sie mit einer großen Anzahl von Spalten arbeiten.
In diesem Fall
do.call()
kommt zur Rettung:quelle
Der Vollständigkeit halber: Sie können auch die
sortByCol()
Funktion aus demBBmisc
Paket verwenden:Leistungsvergleich:
quelle
data.frame
Genau wie bei den mechanischen Kartensortierern von vor langer Zeit, sortieren Sie zuerst nach dem niedrigstwertigen Schlüssel, dann nach dem nächstwertigsten usw. Keine Bibliothek erforderlich, funktioniert mit einer beliebigen Anzahl von Schlüsseln und einer beliebigen Kombination von aufsteigenden und absteigenden Schlüsseln.
Jetzt sind wir bereit, den wichtigsten Schlüssel zu tun. Die Sortierung ist stabil, und alle Bindungen im wichtigsten Schlüssel wurden bereits gelöst.
Dies ist vielleicht nicht die schnellste, aber sicherlich einfach und zuverlässig
quelle
Eine andere Alternative, die das
rgr
Paket verwendet:quelle
Ich hatte Probleme mit den oben genannten Lösungen, als ich meinen Bestellvorgang für n Spalten automatisieren wollte, deren Spaltennamen jedes Mal unterschiedlich sein können. Ich habe eine super hilfreiche Funktion aus dem
psych
Paket gefunden, um dies auf einfache Weise zu tun:Wo
columnIndices
sind Indizes einer oder mehrerer Spalten in der Reihenfolge, in der Sie sie sortieren möchten? Weitere Informationen hier:dfOrder-Funktion aus dem 'psych'-Paket
quelle