wake-up-neo.com

So sortieren Sie einen Datenrahmen nach mehreren Spalten

Ich möchte einen data.frame nach mehreren Spalten sortieren. Mit dem folgenden data.frame möchte ich beispielsweise 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
1245

Sie können die Funktion order() direkt verwenden, ohne auf Add-On-Tools zurückzugreifen - sehen Sie sich diese einfachere Antwort an, die einen Trick direkt am Anfang des Codes für example(order) verwendet:

R> dd[with(dd, order(-z, b)), ]
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1

Bearbeiten Sie einige 2+ Jahre später: Es wurde nur gefragt, wie dies durch den Spaltenindex geschehen soll. Die Antwort ist, einfach die gewünschte (n) Sortierspalte (n) an die Funktion order() zu übergeben:

R> dd[order(-dd[,4], dd[,1]), ]
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1
R> 

anstatt den Namen der Spalte zu verwenden (und with() für einen einfacheren/direkteren Zugriff).

1550

Deine Entscheidungen

  • order von base
  • arrange von dplyr
  • setorder und setorderv aus data.table
  • arrange von plyr
  • sort von taRifx
  • orderBy von doBy
  • sortData von Deducer

Meistens sollten Sie die Lösungen dplyr oder data.table verwenden, es sei denn, es ist wichtig, keine Abhängigkeiten zu haben. In diesem Fall verwenden Sie base::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?

Aus diesem Grund können Sie bei gegebenem data.frame dd wie folgt 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))
library(taRifx)
sort(dd, f= ~ -z + b )

Wenn Sie einer der ursprünglichen Autoren dieser Funktion sind, kontaktieren Sie mich bitte. Die Diskussion über Public Domaininess ist hier: http://chat.stackoverflow.com/transcript/message/1094290#109429


Sie können auch die Funktion arrange() von plyr verwenden, wie Hadley im obigen Thread ausgeführt hat:

library(plyr)
arrange(dd,desc(z),b)

Benchmarks: Beachten Sie, dass ich jedes Paket in einer neuen R-Sitzung geladen habe, da es viele Konflikte gab. Insbesondere das Laden des doBy-Pakets bewirkt, dass sort "Die folgenden Objekte werden von 'x (Position 17)' maskiert: b, x, y, z", und das Laden des Deducer-Pakets überschreibt sort.data.frame von Kevin Wright oder dem taRifx-Paket.

#Load each time
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))
library(microbenchmark)

# Reload R between benchmarks
microbenchmark(dd[with(dd, order(-z, b)), ] ,
    dd[order(-dd$z, dd$b),],
    times=1000
)

Medianzeiten:

dd[with(dd, order(-z, b)), ] 778

dd[order(-dd$z, dd$b),] 788

library(taRifx)
microbenchmark(sort(dd, f= ~-z+b ),times=1000)

Medianzeit: 1.567

library(plyr)
microbenchmark(arrange(dd,desc(z),b),times=1000)

Medianzeit: 862

library(doBy)
microbenchmark(orderBy(~-z+b, data=dd),times=1000)

Medianzeit: 1.694

Beachten Sie, dass das Laden des Pakets durch doBy einige Zeit in Anspruch nimmt.

library(Deducer)
microbenchmark(sortData(dd,c("z","b"),increasing= c(FALSE,TRUE)),times=1000)

Deducer konnte nicht geladen werden. Benötigt JGR-Konsole.

esort <- function(x, sortvar, ...) {
attach(x)
x <- x[with(x,order(sortvar,...)),]
return(x)
detach(x)
}

microbenchmark(esort(dd, -z, b),times=1000)

Scheint aufgrund des Anbringens/Lösens nicht mit dem Mikrobenchmark kompatibel zu sein.


m <- microbenchmark(
  arrange(dd,desc(z),b),
  sort(dd, f= ~-z+b ),
  dd[with(dd, order(-z, b)), ] ,
  dd[order(-dd$z, dd$b),],
  times=1000
  )

uq <- function(x) { fivenum(x)[4]}  
lq <- function(x) { fivenum(x)[2]}

y_min <- 0 # min(by(m$time,m$expr,lq))
y_max <- max(by(m$time,m$expr,uq)) * 1.05

p <- ggplot(m,aes(x=expr,y=time)) + coord_cartesian(ylim = c( y_min , y_max )) 
p + stat_summary(fun.y=median,fun.ymin = lq, fun.ymax = uq, aes(fill=expr))

microbenchmark plot

(Linien erstrecken sich vom unteren zum oberen Quartil, Punkt ist der Median)


Angesichts dieser Ergebnisse und der Einfachheit des Abwägens im Verhältnis zur Geschwindigkeit müsste ich arrange im plyr-Paket nicken. . 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. Meine einzige Beschwerde ist, dass es die Standard-R-Nomenklatur verletzt, in der Sortierobjekte von sort(object) aufgerufen werden, aber ich verstehe, warum Hadley dies aufgrund der in der oben verlinkten Frage diskutierten Probleme so gemacht hat.

441
Ari B. Friedman

Dirks Antwort ist großartig. Außerdem wird ein wesentlicher Unterschied in der Syntax für die Indizierung von _data.frame_ s und _data.table_ s hervorgehoben:

_## The data.frame way
dd[with(dd, order(-z, b)), ]

## The data.table way: (7 fewer characters, but that's not the important bit)
dd[order(-z, b)]
_

Der Unterschied zwischen den beiden Aufrufen ist gering, kann jedoch wichtige Konsequenzen haben. Insbesondere wenn Sie Seriencode schreiben und/oder sich um die Richtigkeit Ihrer Recherche bemühen, ist es am besten, unnötige Wiederholungen von Variablennamen zu vermeiden. _data.table_ hilft Ihnen dabei.

Hier ist ein Beispiel, 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, in dem es viele Objektnamen gibt und sie lang und aussagekräftig sind. anstelle von dd heißt es quarterlyreport. Es wird :

_quarterlyreport[with(quarterlyreport,order(-z,b)),]
_

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 und fügen an verschiedenen Stellen ein Objekt lastquarterlyreport hinzu.

_quarterlyreport[with(lastquarterlyreport,order(-z,b)),]
_

Das haben Sie nicht gemeint, aber Sie haben es nicht bemerkt, weil Sie es schnell gemacht haben und es auf einer Seite mit ähnlichem Code eingebettet ist. 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, es bemerkt, aber vielleicht tun sie es 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.

In data.table geht es uns um so kleine Details. Wir haben also etwas Einfaches getan, um zu vermeiden, dass Variablennamen zweimal eingegeben werden. Etwas sehr Einfaches. i wird bereits im Rahmen von dd automatisch ausgewertet. Sie brauchen with() überhaupt nicht.

Anstatt von

_dd[with(dd, order(-z, b)), ]
_

es ist nur

_dd[order(-z, b)]
_

Und statt

_quarterlyreport[with(lastquarterlyreport,order(-z,b)),]
_

es ist nur

_quarterlyreport[order(-z,b)]
_

Es ist ein sehr kleiner Unterschied, aber es könnte eines Tages Ihren Nacken 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 haben keine.

141
Matt Dowle

Hier gibt es viele ausgezeichnete Antworten, aber dplyr gibt die einzige Syntax an, an die ich mich schnell und einfach erinnern kann (und die ich jetzt sehr oft verwende):

library(dplyr)
# sort mtcars by mpg, ascending... use desc(mpg) for descending
arrange(mtcars, mpg)
# sort mtcars first by mpg, then by cyl, then by wt)
arrange(mtcars , mpg, cyl, wt)

Für das OP-Problem:

arrange(dd, desc(z),  b)

    b x y z
1 Low C 9 2
2 Med D 3 1
3  Hi A 8 1
4  Hi A 9 1
117
Ben

Das R-Paket _data.table_ bietet sowohl schnelle als auch speichereffiziente Reihenfolge von Datentabellen mit einer einfachen Syntax (von der Matt einen Teil sehr schön hervorgehoben hat in seiner Antwort ). Seitdem gab es eine ganze Reihe von Verbesserungen und auch eine neue Funktion setorder(). Ab _v1.9.5+_ funktioniert setorder() auch mit data.frames .

Zuerst erstellen wir einen ausreichend großen Datensatz und vergleichen die verschiedenen Methoden, die aus anderen Antworten hervorgehen, und listen dann die Funktionen von data.table auf.

Daten:

_require(plyr)
require(doBy)
require(data.table)
require(dplyr)
require(taRifx)

set.seed(45L)
dat = data.frame(b = as.factor(sample(c("Hi", "Med", "Low"), 1e8, TRUE)),
                 x = sample(c("A", "D", "C"), 1e8, TRUE),
                 y = sample(100, 1e8, TRUE),
                 z = sample(5, 1e8, TRUE), 
                 stringsAsFactors = FALSE)
_

Benchmarks:

Die angegebenen Timings beziehen sich auf die Ausführung von system.time(...) für diese unten gezeigten Funktionen. Die Timings sind in der folgenden Tabelle aufgeführt (in der Reihenfolge der langsamsten bis schnellsten).

_orderBy( ~ -z + b, data = dat)     ## doBy
plyr::arrange(dat, desc(z), b)     ## plyr
arrange(dat, desc(z), b)           ## dplyr
sort(dat, f = ~ -z + b)            ## taRifx
dat[with(dat, order(-z, b)), ]     ## base R

# convert to data.table, by reference
setDT(dat)

dat[order(-z, b)]                  ## data.table, base R like syntax
setorder(dat, -z, b)               ## data.table, using setorder()
                                   ## setorder() now also works with data.frames 

# R-session memory usage (BEFORE) = ~2GB (size of 'dat')
# ------------------------------------------------------------
# Package      function    Time (s)  Peak memory   Memory used
# ------------------------------------------------------------
# doBy          orderBy      409.7        6.7 GB        4.7 GB
# taRifx           sort      400.8        6.7 GB        4.7 GB
# plyr          arrange      318.8        5.6 GB        3.6 GB 
# base R          order      299.0        5.6 GB        3.6 GB
# dplyr         arrange       62.7        4.2 GB        2.2 GB
# ------------------------------------------------------------
# data.table      order        6.2        4.2 GB        2.2 GB
# data.table   setorder        4.5        2.4 GB        0.4 GB
# ------------------------------------------------------------
_
  • Die DT[order(...)] - Syntax von _data.table_ war ~ 10x schneller als die schnellste aller anderen Methoden (dplyr), während sie die Gleiche Speicherkapazität wie dplyr.

  • setorder() von _data.table war ~ 14x schneller als die schnellste der anderen Methoden (dplyr), während nur 0,4 GB zusätzlicher Speicher . dat befindet sich jetzt in der von uns benötigten Reihenfolge (da es durch Verweis aktualisiert wird).

funktionen von data.table:

Geschwindigkeit:

  • Die Reihenfolge von data.table ist extrem schnell, da radix ordering implementiert wird.

  • Die Syntax DT[order(...)] ist intern optimiert, um auch die schnelle Reihenfolge von data.table zu verwenden. Sie können die gewohnte Basis-R-Syntax beibehalten, aber den Prozess beschleunigen (und weniger Speicher verwenden).

Speicher:

  • In den meisten Fällen benötigen wir nach der Neuordnung nicht die ursprünglichen data.frame oder data.table . Das heißt, wir weisen das Ergebnis normalerweise demselben Objekt zu, zum Beispiel:

    _DF <- DF[order(...)]
    _

    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.tables _by reference_ ( in-place ) neu an, ohne zusätzliche Kopien anzufertigen. Es wird nur zusätzlicher Speicher verwendet, der der Größe einer Spalte entspricht.

Weitere Funktionen:

  1. Es werden die Typen integer, logical, numeric, character und sogar _bit64::integer64_ unterstützt.

    Beachten Sie, dass die Klassen factor, Date, POSIXct usw. alle integer/numeric -Typen mit zusätzlichen Attributen sind und daher ebenfalls unterstützt werden.

  2. In der Basis R können wir _-_ nicht für einen Zeichenvektor verwenden, um nach dieser Spalte in absteigender Reihenfolge zu sortieren. Stattdessen müssen wir -xtfrm(.) verwenden.

    In data.table können wir jedoch beispielsweise nur dat[order(-x)] oder setorder(dat, -x) ausführen.

77
Arun

Mit dieser (sehr hilfreichen) Funktion von Kevin Wright , die im Tipps-Bereich des R-Wikis veröffentlicht ist, ist dies leicht zu erreichen.

sort(dd,by = ~ -z + b)
#     b x y z
# 4 Low C 9 2
# 2 Med D 3 1
# 1  Hi A 8 1
# 3  Hi A 9 1
67

oder Sie können das Paket doBy verwenden

library(doBy)
dd <- orderBy(~-z+b, data=dd)
35
George Dontas

Angenommen, Sie haben einen data.frameA und möchten ihn nach der Spalte x in absteigender Reihenfolge sortieren. Rufen Sie den sortierten data.framenewdata auf

newdata <- A[order(-A$x),]

Wenn Sie eine aufsteigende Reihenfolge wünschen, ersetzen Sie "-" durch nichts. Sie können so etwas haben

newdata <- A[order(-A$x, A$y, -A$z),]

dabei sind x und z einige Spalten in data.frameA. Dies bedeutet, dass data.frameA nach x absteigend, y aufsteigend und z absteigend sortiert wird.

34
Khayelihle

wenn SQL für Sie selbstverständlich ist, behandelt sqldf ORDER BY wie von Codd vorgesehen.

27
malecki

Alternativ können Sie das Paket Deducer verwenden

library(Deducer)
dd<- sortData(dd,c("z","b"),increasing= c(FALSE,TRUE))
27
Ian Fellows

Als Antwort auf einen Kommentar im OP zum programmgesteuerten Sortieren:

dplyr und data.table verwenden

library(dplyr)
library(data.table)

dplyr

Verwenden Sie einfach arrange_, die Standard-Evaluierungsversion für arrange.

df1 <- tbl_df(iris)
#using strings or formula
arrange_(df1, c('Petal.Length', 'Petal.Width'))
arrange_(df1, ~Petal.Length, ~Petal.Width)
    Source: local data frame [150 x 5]

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
          (dbl)       (dbl)        (dbl)       (dbl)  (fctr)
1           4.6         3.6          1.0         0.2  setosa
2           4.3         3.0          1.1         0.1  setosa
3           5.8         4.0          1.2         0.2  setosa
4           5.0         3.2          1.2         0.2  setosa
5           4.7         3.2          1.3         0.2  setosa
6           5.4         3.9          1.3         0.4  setosa
7           5.5         3.5          1.3         0.2  setosa
8           4.4         3.0          1.3         0.2  setosa
9           5.0         3.5          1.3         0.3  setosa
10          4.5         2.3          1.3         0.3  setosa
..          ...         ...          ...         ...     ...


#Or using a variable
sortBy <- c('Petal.Length', 'Petal.Width')
arrange_(df1, .dots = sortBy)
    Source: local data frame [150 x 5]

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
          (dbl)       (dbl)        (dbl)       (dbl)  (fctr)
1           4.6         3.6          1.0         0.2  setosa
2           4.3         3.0          1.1         0.1  setosa
3           5.8         4.0          1.2         0.2  setosa
4           5.0         3.2          1.2         0.2  setosa
5           4.7         3.2          1.3         0.2  setosa
6           5.5         3.5          1.3         0.2  setosa
7           4.4         3.0          1.3         0.2  setosa
8           4.4         3.2          1.3         0.2  setosa
9           5.0         3.5          1.3         0.3  setosa
10          4.5         2.3          1.3         0.3  setosa
..          ...         ...          ...         ...     ...

#Doing the same operation except sorting Petal.Length in descending order
sortByDesc <- c('desc(Petal.Length)', 'Petal.Width')
arrange_(df1, .dots = sortByDesc)

weitere Informationen hier: https://cran.r-project.org/web/packages/dplyr/vignettes/nse.html

Es ist besser, Formel zu verwenden, da dadurch auch die Umgebung erfasst wird, in der ein Ausdruck ausgewertet wird

datentabelle

dt1 <- data.table(iris) #not really required, as you can work directly on your data.frame
sortBy <- c('Petal.Length', 'Petal.Width')
sortType <- c(-1, 1)
setorderv(dt1, sortBy, sortType)
dt1
     Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
  1:          7.7         2.6          6.9         2.3 virginica
  2:          7.7         2.8          6.7         2.0 virginica
  3:          7.7         3.8          6.7         2.2 virginica
  4:          7.6         3.0          6.6         2.1 virginica
  5:          7.9         3.8          6.4         2.0 virginica
 ---                                                            
146:          5.4         3.9          1.3         0.4    setosa
147:          5.8         4.0          1.2         0.2    setosa
148:          5.0         3.2          1.2         0.2    setosa
149:          4.3         3.0          1.1         0.1    setosa
150:          4.6         3.6          1.0         0.2    setosa
15
info_seekeR

Die Antwort von Dirk 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:

dd <- dd[with(dd, order(-z, b)), ] 
15
Andrew

Ich habe mit dem folgenden Beispiel von order erfahren, was mich dann lange verwirrt hat:

set.seed(1234)

ID        = 1:10
Age       = round(rnorm(10, 50, 1))
diag      = c("Depression", "Bipolar")
Diagnosis = sample(diag, 10, replace=TRUE)

data = data.frame(ID, Age, Diagnosis)

databyAge = data[order(Age),]
databyAge

Der einzige Grund, warum dieses Beispiel funktioniert, ist, dass order nach vector Age sortiert wird, nicht nach der Spalte Age in data frame data.

Um dies zu sehen, erstellen Sie einen identischen Datenrahmen mit read.table mit leicht unterschiedlichen Spaltennamen und ohne Verwendung eines der oben genannten Vektoren:

my.data <- read.table(text = '

  id age  diagnosis
   1  49 Depression
   2  50 Depression
   3  51 Depression
   4  48 Depression
   5  50 Depression
   6  51    Bipolar
   7  49    Bipolar
   8  49    Bipolar
   9  49    Bipolar
  10  49 Depression

', header = TRUE)

Die obige Zeilenstruktur für order funktioniert nicht mehr, da es keinen Vektor mit dem Namen age gibt:

databyage = my.data[order(age),]

Die folgende Zeile funktioniert, weil order in der Spalte age in my.data sortiert wird.

databyage = my.data[order(my.data$age),]

Ich dachte, das wäre eine Veröffentlichung wert, da ich so lange durch dieses Beispiel verwirrt war. Wenn dieser Beitrag nicht für den Thread geeignet ist, kann ich ihn entfernen.

EDIT: 13. Mai 2014

Im Folgenden finden Sie eine verallgemeinerte Methode zum Sortieren eines Datenrahmens nach jeder Spalte ohne Angabe von Spaltennamen. 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 umfangreichen und schwierigen Suchen. Ich bin mir nicht sicher, ob ich diesen Posten jetzt verlagern könnte. Der aktuelle Thread ist der erste Treffer für die Bestellung eines data.frame in R. Also dachte ich, meine erweiterte Version dieses ursprünglichen do.call Codes könnte nützlich sein.

set.seed(1234)

v1  <- c(0,0,0,0, 0,0,0,0, 1,1,1,1, 1,1,1,1)
v2  <- c(0,0,0,0, 1,1,1,1, 0,0,0,0, 1,1,1,1)
v3  <- c(0,0,1,1, 0,0,1,1, 0,0,1,1, 0,0,1,1)
v4  <- c(0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1)

df.1 <- data.frame(v1, v2, v3, v4) 
df.1

rdf.1 <- df.1[sample(nrow(df.1), nrow(df.1), replace = FALSE),]
rdf.1

order.rdf.1 <- rdf.1[do.call(order, as.list(rdf.1)),]
order.rdf.1

order.rdf.2 <- rdf.1[do.call(order, rev(as.list(rdf.1))),]
order.rdf.2

rdf.3 <- data.frame(rdf.1$v2, rdf.1$v4, rdf.1$v3, rdf.1$v1) 
rdf.3

order.rdf.3 <- rdf.1[do.call(order, as.list(rdf.3)),]
order.rdf.3
15
Mark Miller

Das arrang () in dplyr ist meine Lieblingsoption. Verwenden Sie den Pipe-Operator und gehen Sie vom unwichtigsten zum wichtigsten Aspekt über

dd1 <- dd %>%
    arrange(z) %>%
    arrange(desc(x))
9
Kaden Killpack

Der Vollständigkeit halber: Sie können auch die Funktion sortByCol() aus dem Paket BBmisc verwenden:

library(BBmisc)
sortByCol(dd, c("z", "b"), asc = c(FALSE, TRUE))
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1

Leistungsvergleich:

library(microbenchmark)
microbenchmark(sortByCol(dd, c("z", "b"), asc = c(FALSE, TRUE)), times = 100000)
median 202.878

library(plyr)
microbenchmark(arrange(dd,desc(z),b),times=100000)
median 148.758

microbenchmark(dd[with(dd, order(-z, b)), ], times = 100000)
median 115.872
5
Lars Kotthoff

Genau wie bei den mechanischen Kartensortierern von vor langer Zeit, sortieren Sie zuerst nach dem niedrigstwertigen Schlüssel, dann nach dem nächsthöheren usw. Keine Bibliothek erforderlich, funktioniert mit einer beliebigen Anzahl von Schlüsseln und einer beliebigen Kombination von aufsteigenden und absteigenden Schlüsseln.

 dd <- dd[order(dd$b, decreasing = FALSE),]

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.

dd <- dd[order(dd$z, decreasing = TRUE),]

Dies ist vielleicht nicht die schnellste, aber es ist sicherlich einfach und zuverlässig

4
Rick

Eine weitere Alternative mit dem Paket rgr:

> library(rgr)
> gx.sort.df(dd, ~ -z+b)
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1
3

Nur der Vollständigkeit halber, da nicht viel über das Sortieren nach Spaltennummern gesagt wurde ... Es kann sicherlich argumentiert werden, dass es oft nicht wünschenswert ist (da 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 das 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 kommt do.call() zur Rettung:

ind <- do.call(what = "order", args = iris[,c(5,1,2,3)])
iris[ind, ]

##        Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
##    14           4.3         3.0          1.1         0.1     setosa
##    9            4.4         2.9          1.4         0.2     setosa
##    39           4.4         3.0          1.3         0.2     setosa
##    43           4.4         3.2          1.3         0.2     setosa
##    42           4.5         2.3          1.3         0.3     setosa
##    4            4.6         3.1          1.5         0.2     setosa
##    48           4.6         3.2          1.4         0.2     setosa
##    7            4.6         3.4          1.4         0.3     setosa
##    (...)
2
Dominic Comtois

Ich hatte Probleme mit den oben genannten Lösungen, als ich meinen Bestellvorgang für n Spalten automatisieren wollte, deren Spaltennamen jedes Mal anders sein können. Ich habe eine super hilfreiche Funktion aus dem psych -Paket gefunden, um dies auf einfache Weise zu tun:

dfOrder(myDf, columnIndices)

dabei ist columnIndices der Index einer oder mehrerer Spalten in der Reihenfolge, in der Sie sie sortieren möchten. Weitere Informationen hier:

dfOrder-Funktion aus dem 'psych'-Paket

2
AHegde