1504 Stimmen

Sortieren Sie die Zeilen des Datenrahmens nach mehreren Spalten.

Ich möchte ein Datenrahmen nach mehreren Spalten sortieren. Zum Beispiel würde ich gerne mit dem unten stehenden Datenrahmen nach der Spalte 'z' (absteigend) und dann nach der 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

28voto

Kaden Killpack Punkte 381

Die arrange()-Funktion in dplyr ist meine Lieblingsoption. Verwenden Sie den Pipe-Operator und gehen Sie vom am wenigsten wichtigen zum wichtigsten Aspekt.

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

28voto

info_seekeR Punkte 1304

Als Antwort auf einen im OP hinzugefügten Kommentar zur programmatischen Sortierung:

Verwendung von dplyr und data.table

library(dplyr)
library(data.table)

dplyr

Verwenden Sie einfach arrange_, die Standardauswertungsversion für arrange.

df1 <- tbl_df(iris)
#mit Zeichenketten oder Formel
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
..          ...         ...          ...         ...     ...

#Oder Verwendung einer 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
..          ...         ...          ...         ...     ...

#Dasselbe tun, außer dass Petal.Length absteigend sortiert wird
sortByDesc <- c('desc(Petal.Length)', 'Petal.Width')
arrange_(df1, .dots = sortByDesc)

mehr Info 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, um einen Ausdruck auszuwerten

data.table

dt1 <- data.table(iris) #nicht wirklich erforderlich, da Sie direkt an Ihrem data.frame arbeiten können
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

26voto

Mark Miller Punkte 11771

Ich habe mit dem folgenden Beispiel das Konzept von order gelernt, was mich dann lange Zeit 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, weil order nach dem Vektor Age sortiert und nicht nach der Spalte namens Age im Datenrahmen data.

Um dies zu sehen, erstelle einen identischen Datenrahmen mit read.table und leicht unterschiedlichen Spaltennamen ohne Verwendung 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 oben genannte Struktur für order funktioniert nicht mehr, weil es keinen Vektor namens age gibt:

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

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

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

Ich dachte, es sei sinnvoll, dies zu posten, da ich lange Zeit von diesem Beispiel verwirrt war. Wenn dieser Beitrag nicht für den Thread geeignet ist, kann ich ihn entfernen.

BEARBEITEN: 13. Mai 2014

Nachfolgend finden Sie eine verallgemeinerte Methode zum Sortieren eines Datensatzes nach jeder Spalte, ohne die Spaltennamen anzugeben. Der untenstehende Code zeigt, wie man von links nach rechts oder von rechts nach links sortiert. Dies funktioniert, wenn jede Spalte numerisch ist. Ich habe es noch nicht mit einer Zeichenkette probiert.

Ich habe den do.call Code vor einem Monat oder zwei in einem alten Beitrag auf einer anderen Website gefunden, nach umfangreicher und schwieriger Suche. Ich bin mir nicht sicher, ob ich diesen Beitrag jetzt wiederfinden könnte. Der vorliegende Thread ist der erste Treffer für das Sortieren eines Datenrahmens in R. Daher dachte ich, dass meine erweiterte Version des ursprünglichen do.call Codes nützlich sein könnte.

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

5 Stimmen

Diese Syntax funktioniert, wenn Sie Ihre Daten in einem data.table speichern, anstelle eines data.frames: require(data.table); my.dt <- data.table(my.data); my.dt[order(age)] Dies funktioniert, weil die Spaltennamen innerhalb der [] Klammern verfügbar gemacht werden.

1 Stimmen

Ich glaube nicht, dass der Downvote hier notwendig ist, aber ich glaube auch nicht, dass dies viel zur Frage beiträgt, insbesondere angesichts des vorhandenen Satzes von Antworten, von denen einige bereits das erforderliche mit data.frames erfassen, um entweder with oder $ zu verwenden.

2 Stimmen

Upvote für do.call das erleichtert die Sortierung eines Datenrahmens mit mehreren Spalten erheblich. Einfach do.call(sort, mydf.obj) und eine schöne Kaskadensortierung wird erreicht.

23voto

Andrew Punkte 8719

Dirks Antwort ist gut, aber wenn Sie möchten, dass die Sortierung bestehen bleibt, möchten Sie die Sortierung wieder auf den Namen dieses Datenrahmens anwenden. Verwenden Sie den Beispielcode:

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

12voto

Dominic Comtois Punkte 10020

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 (weil die Reihenfolge der Spalten sich ändern könnte, was zu Fehlern führen könnte), aber in einigen spezifischen Situationen (wenn man beispielsweise eine schnelle Arbeit erledigen muss und es keine Gefahr gibt, dass sich die Reihenfolge der Spalten ändert), könnte es das Vernünftigste sein, insbesondere wenn man mit großen Mengen von Spalten umgeht.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X