Ordnen Sie die Ebenen eines Faktors neu an, ohne die Reihenfolge der Werte zu ändern

124

Ich habe einen Datenrahmen mit einigen numerischen Variablen und einigen kategorialen factorVariablen. Die Reihenfolge der Ebenen für diese Faktoren ist nicht so, wie ich sie haben möchte.

numbers <- 1:4
letters <- factor(c("a", "b", "c", "d"))
df <- data.frame(numbers, letters)
df
#   numbers letters
# 1       1       a
# 2       2       b
# 3       3       c
# 4       4       d

Wenn ich die Reihenfolge der Ebenen ändere, sind die Buchstaben nicht mehr mit den entsprechenden Zahlen versehen (meine Daten sind ab diesem Zeitpunkt völliger Unsinn).

levels(df$letters) <- c("d", "c", "b", "a")
df
#   numbers letters
# 1       1       d
# 2       2       c
# 3       3       b
# 4       4       a

Ich mag einfach das ändern Ebene um, so beim Plotten, die Stangen in der gewünschten Reihenfolge angezeigt - was von Standard alphabetischer Reihenfolge abweichen.

Crangos
quelle
1
Könnte mir jemand einen Hinweis geben, warum die Zuordnung zu Ebenen (...) die Reihenfolge der Einträge im Datenrahmen ändert, wie Crangos in der Frage zeigt? Es scheint mir schrecklich unintuitiv und unerwünscht. Ich habe einige Zeit damit verbracht, ein Problem zu debuggen, das heute selbst dadurch verursacht wurde. Ich denke, es könnte einen Grund für dieses Verhalten geben, den ich nicht sehen kann, oder zumindest eine vernünftige Erklärung dafür, warum es passiert.
Anton

Antworten:

120

Verwenden Sie das levelsArgument von factor:

df <- data.frame(f = 1:4, g = letters[1:4])
df
#   f g
# 1 1 a
# 2 2 b
# 3 3 c
# 4 4 d

levels(df$g)
# [1] "a" "b" "c" "d"

df$g <- factor(df$g, levels = letters[4:1])
# levels(df$g)
# [1] "d" "c" "b" "a"

df
#   f g
# 1 1 a
# 2 2 b
# 3 3 c
# 4 4 d
Jonathan Chang
quelle
1
Danke, das hat funktioniert. Aus irgendeinem seltsamen Grund hat ggplot jetzt die Reihenfolge in der Legende korrekt geändert, jedoch nicht in der Handlung. Seltsam.
Crangos
7
Bei ggplot2 musste ich sowohl die Reihenfolge der Ebenen (siehe oben) als auch die Reihenfolge der Werte des Datenrahmens ändern. df <- df [nrow (df): 1,] # reverse
crangos
@crangos, ich denke, ggplot verwendet die alphabetische Reihenfolge der Ebenen und ignoriert manchmal benutzerdefinierte Faktorstufen. Bitte bestätigen Sie und geben Sie die Versionsnummer an.
smci
22

einige mehr, nur für die Aufzeichnung

## reorder is a base function
df$letters <- reorder(df$letters, new.order=letters[4:1])

library(gdata)
df$letters <- reorder.factor(df$letters, letters[4:1])

Möglicherweise finden Sie auch nützliche Relevel- und Kombinationsfaktoren .

George Dontas
quelle
2
Ihre erste Antwort funktioniert bei mir nicht. Aber das funktioniert:reorder(df$letters, seq(4,1))
Alex Holcombe
1
Ich habe eine sehr seltsame Situation, in der die Nachbestellung für einen Datensatz funktioniert, nicht für einen anderen. Auf dem anderen Datensatz wird der Fehler "Fehler beim Tapply (X = X, INDEX = x, FUN = FUN, ...) ausgegeben: Argument" X "fehlt ohne Standard". Ich bin mir nicht sicher, was die Lösung für dieses Problem ist. Ich kann keinen relevanten Unterschied zwischen den Datensätzen feststellen.
CoderGuy123
10

Seit diese Frage zuletzt aktiv war, hat Hadley sein neues forcatsPaket zur Manipulation von Faktoren veröffentlicht, und ich finde es unglaublich nützlich. Beispiele aus dem Datenrahmen des OP:

levels(df$letters)
# [1] "a" "b" "c" "d"

So kehren Sie die Ebenen um:

library(forcats)
fct_rev(df$letters) %>% levels
# [1] "d" "c" "b" "a"

So fügen Sie weitere Ebenen hinzu:

fct_expand(df$letters, "e") %>% levels
# [1] "a" "b" "c" "d" "e"

Und viele weitere nützliche fct_xxx()Funktionen.

Joe
quelle
Ist das noch verfügbar?
Joshua Rosenberg
1
Sie möchten einen Code wie folgt schreiben : df %>% mutate(letters = fct_rev(letters)).
Jazzurro
9

so , was Sie wollen, in R Lexikon, ist nur die Änderungen Etiketten für einen bestimmten Faktor Variablen (dh, lassen Sie die Daten als auch die Faktorstufen , unverändert).

df$letters = factor(df$letters, labels=c("d", "c", "b", "a"))

Da Sie nur die Zuordnung von Datenpunkt zu Beschriftung und nicht die Daten oder das Faktorschema ändern möchten (wie die Datenpunkte in einzelne Fächer oder Faktorwerte unterteilt werden, ist es möglicherweise hilfreich zu wissen, wie die Zuordnung ursprünglich festgelegt wurde, als Sie sie zum ersten Mal erstellen der Faktor.

Die Regeln sind einfach:

  • Etiketten werden durch den Indexwert auf Ebenen abgebildet (dh der Wert auf den Ebenen [2] erhält das Etikett, Etikett [2]);
  • Faktorstufen können explizit festgelegt werden, indem sie über das Argument Ebenen übergeben werden . oder
  • Wenn kein Wert für das Argument Ebene zugeführt wird, wird der Standardwert verwendet , die das Ergebnis ruft einzigartig auf dem Datenvektor (für die übergebenen Daten argument);
  • Beschriftungen können explizit über das Beschriftungsargument festgelegt werden. oder
  • Wenn für das Label-Argument kein Wert angegeben wird, wird der Standardwert verwendet, der nur der Ebenenvektor ist
Doug
quelle
1
Ich weiß nicht, warum dies nicht so gut abgestimmt ist wie die akzeptierte Antwort. Das ist viel informativer.
Rambatino
12
Wenn Sie diesen Ansatz verwenden, werden Ihre Daten falsch beschriftet.
Nazer
4
Eigentlich weiß ich nicht, was ich damit anfangen soll. Die Antwort scheint zu beabsichtigen, die Daten zum Plotten falsch zu kennzeichnen. Pfui. zurück zum Original gerollt. Benutzer
aufgepasst
7

Der Umgang mit Faktoren in R ist eine ziemlich eigenartige Aufgabe, muss ich zugeben ... Während Sie die Faktorstufen neu ordnen, ordnen Sie die zugrunde liegenden numerischen Werte nicht neu. Hier ist eine kleine Demonstration:

> numbers = 1:4
> letters = factor(letters[1:4])
> dtf <- data.frame(numbers, letters)
> dtf
  numbers letters
1       1       a
2       2       b
3       3       c
4       4       d
> sapply(dtf, class)
  numbers   letters 
"integer"  "factor" 

Wenn Sie diesen Faktor in numerisch umwandeln, erhalten Sie:

# return underlying numerical values
1> with(dtf, as.numeric(letters))
[1] 1 2 3 4
# change levels
1> levels(dtf$letters) <- letters[4:1]
1> dtf
  numbers letters
1       1       d
2       2       c
3       3       b
4       4       a
# return numerical values once again
1> with(dtf, as.numeric(letters))
[1] 1 2 3 4

Wie Sie sehen können ... ändern Sie durch Ändern der Ebenen nur die Ebenen (wer würde das sagen, was?), Nicht die numerischen Werte! Wenn Sie jedoch die factorvon @Jonathan Chang vorgeschlagene Funktion verwenden, passiert etwas anderes: Sie ändern die numerischen Werte selbst.

Sie erhalten erneut einen Fehler, weil Sie dies tun levelsund dann versuchen, ihn mit neu zu bewerten factor. Tu es nicht !!! Sie nicht verwenden , levelsoder Sie werden durcheinander zu bringen (es sei denn , Sie wissen genau , was Sie tun).

Ein kleiner Vorschlag: Vermeiden Sie es, Ihre Objekte mit einem identischen Namen wie die Objekte von R zu benennen ( dfist Dichtefunktion für die F-Verteilung, lettersgibt Kleinbuchstaben an). In diesem speziellen Fall wäre Ihr Code nicht fehlerhaft, aber manchmal kann es sein ... aber dies kann Verwirrung stiften, und das wollen wir nicht, oder?!? =)

Verwenden Sie stattdessen so etwas (ich gehe noch einmal von Anfang an):

> dtf <- data.frame(f = 1:4, g = factor(letters[1:4]))
> dtf
  f g
1 1 a
2 2 b
3 3 c
4 4 d
> with(dtf, as.numeric(g))
[1] 1 2 3 4
> dtf$g <- factor(dtf$g, levels = letters[4:1])
> dtf
  f g
1 1 a
2 2 b
3 3 c
4 4 d
> with(dtf, as.numeric(g))
[1] 4 3 2 1

Beachten Sie, dass Sie Sie auch data.framemit dfund lettersanstelle von benennen können gund das Ergebnis in Ordnung ist. Tatsächlich ist dieser Code mit dem von Ihnen geposteten identisch, nur die Namen werden geändert. Dieser Teil factor(dtf$letter, levels = letters[4:1])würde keinen Fehler auslösen, kann aber verwirrend sein!

Lesen Sie das ?factorHandbuch sorgfältig durch! Was ist der Unterschied zwischen factor(g, levels = letters[4:1])und factor(g, labels = letters[4:1])? Was ist ähnlich in levels(g) <- letters[4:1]und g <- factor(g, labels = letters[4:1])?

Sie können die ggplot-Syntax verwenden, damit wir Ihnen in diesem Fall weiterhelfen können!

Prost!!!

Bearbeiten:

ggplot2erfordert eigentlich, sowohl Ebenen als auch Werte zu ändern? Hm ... ich werde das hier ausgraben ...

aL3xa
quelle
3

Ich möchte einen weiteren Fall hinzufügen, in dem die Ebenen Zeichenfolgen sein könnten, die Zahlen zusammen mit einigen Sonderzeichen tragen: wie im folgenden Beispiel

df <- data.frame(x = c("15-25", "0-4", "5-10", "11-14", "100+"))

Die Standardwerte von xsind:

df$x
# [1] 15-25 0-4   5-10  11-14 100+ 
# Levels: 0-4 100+ 11-14 15-25 5-10

Wenn wir hier die Faktorstufen gemäß dem numerischen Wert neu anordnen möchten, ohne die Stufen explizit aufzuschreiben, können wir Folgendes tun

library(gtools)
df$x <- factor(df$x, levels = mixedsort(df$x))

df$x
# [1] 15-25 0-4   5-10  11-14 100+ 
# Levels: 0-4 5-10 11-14 15-25 100+
as.numeric(df$x)
# [1] 4 1 2 3 5

Ich hoffe, dass dies als nützliche Information für zukünftige Leser angesehen werden kann.

joel.wilson
quelle
0

Hier ist meine Funktion, um Faktoren eines bestimmten Datenrahmens neu zu ordnen:

reorderFactors <- function(df, column = "my_column_name", 
                           desired_level_order = c("fac1", "fac2", "fac3")) {

  x = df[[column]]
  lvls_src = levels(x) 

  idxs_target <- vector(mode="numeric", length=0)
  for (target in desired_level_order) {
    idxs_target <- c(idxs_target, which(lvls_src == target))
  }

  x_new <- factor(x,levels(x)[idxs_target])

  df[[column]] <- x_new

  return (df)
}

Verwendung: reorderFactors(df, "my_col", desired_level_order = c("how","I","want"))

Boern
quelle