J’ai un bloc de données avec des variables numériques et des variables de factor
catégoriques. L’ordre des niveaux pour ces facteurs n’est pas comme je le souhaite.
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
Si je change l’ordre des niveaux, les lettres ne sont plus avec leurs numéros correspondants (mes données sont un non-sens total à partir de ce moment).
levels(df$letters) <- c("d", "c", "b", "a") df # numbers letters # 1 1 d # 2 2 c # 3 3 b # 4 4 a
Je veux simplement changer l’ordre des niveaux , donc lors du traçage, les barres sont affichées dans l’ordre souhaité, ce qui peut différer de l’ordre alphabétique par défaut.
Utilisez l’argument de levels
de factor
:
df <- data.frame(f = 1:4, g = letters[1:4]) df # fg # 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 # fg # 1 1 a # 2 2 b # 3 3 c # 4 4 d
un peu plus, juste pour le compte rendu
## 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])
Vous pouvez également trouver utile Relevel et combine_factor .
Donc, ce que vous voulez, dans Lexicon, c’est de ne modifier que les étiquettes pour une variable de facteur donnée (c.-à-d. laisser les données ainsi que les niveaux de facteurs inchangés).
df$letters = factor(df$letters, labels=c("d", "c", "b", "a"))
étant donné que vous ne souhaitez modifier que le mappage point à point et non le schéma de données ou de facteur (la manière dont les points de données sont regroupés dans des bacs individuels ou des valeurs de facteur, il peut être utile de savoir comment le facteur.
les règles sont simples:
Faire face à des facteurs dans R est un travail assez particulier, je dois admettre … En réorganisant les niveaux de facteur, vous ne réorganisez pas les valeurs numériques sous-jacentes. Voici une petite démonstration:
> 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"
Maintenant, si vous convertissez ce facteur en numérique, vous obtiendrez:
# 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
Comme vous pouvez le voir … en changeant de niveau, vous ne modifiez que les niveaux (qui dirait, hein?), Pas les valeurs numériques! Mais, lorsque vous utilisez la fonction factor
comme l’a suggéré @ Jonathan Chang, quelque chose de différent se produit: vous modifiez les valeurs numériques elles-mêmes.
Vous obtenez encore une fois une erreur parce que vous faites des levels
et que vous essayez de le mettre en évidence avec un factor
. Ne le fais pas !!! N’utilisez pas de levels
ou vous risquez de tout gâcher (sauf si vous savez exactement ce que vous faites).
Une suggestion simple: évitez de nommer vos objects avec un nom identique à celui des objects de R ( df
est la fonction de densité pour la dissortingbution F, les letters
donnent des lettres alphabétiques minuscules). Dans ce cas particulier, votre code ne serait pas défectueux, mais parfois cela peut être … mais cela peut créer de la confusion, et nous ne le voulons pas, n’est-ce pas?!? =)
Au lieu de cela, utilisez quelque chose comme ça (je recommencerai dès le début):
> dtf <- data.frame(f = 1:4, g = factor(letters[1:4])) > dtf fg 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 fg 1 1 a 2 2 b 3 3 c 4 4 d > with(dtf, as.numeric(g)) [1] 4 3 2 1
Notez que vous pouvez également vous nommer data.frame
avec df
et des letters
au lieu de g
, et le résultat sera OK. En fait, ce code est identique à celui que vous avez posté, seuls les noms sont modifiés. Ce factor(dtf$letter, levels = letters[4:1])
ne produirait pas d’erreur, mais cela peut être source de confusion!
Lisez attentivement le manuel du ?factor
Quelle est la différence entre le factor(g, levels = letters[4:1])
et le factor(g, labels = letters[4:1])
? Qu’est-ce qui est similaire dans les levels(g) <- letters[4:1]
et g <- factor(g, labels = letters[4:1])
?
Vous pouvez mettre la syntaxe de ggplot, donc nous pouvons vous aider plus sur celui-ci!
À votre santé!!!
Modifier:
ggplot2
nécessite réellement de changer les niveaux et les valeurs? Hm ... Je vais creuser celui-ci ...
Depuis la dernière fois que cette question a été posée, Hadley a publié son nouveau package forcats
pour manipuler les facteurs et je trouve cela extrêmement utile. Exemples du bloc de données du PO:
levels(df$letters) # [1] "a" "b" "c" "d"
Pour inverser les niveaux:
library(forcats) fct_rev(df$letters) %>% levels # [1] "d" "c" "b" "a"
Pour append plus de niveaux:
fct_expand(df$letters, "e") %>% levels # [1] "a" "b" "c" "d" "e"
Et beaucoup d’autres fonctions fct_xxx()
utiles.
Je souhaite append un autre cas où les niveaux pourraient être des chaînes portant des nombres avec des caractères spéciaux: comme dans l’exemple ci-dessous
df <- data.frame(x = c("15-25", "0-4", "5-10", "11-14", "100+"))
Les niveaux par défaut de x
sont:
df$x # [1] 15-25 0-4 5-10 11-14 100+ # Levels: 0-4 100+ 11-14 15-25 5-10
Ici, si nous voulons réorganiser les niveaux de facteur en fonction de la valeur numérique, sans écrire explicitement les niveaux, nous pourrions faire
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
J'espère que cela peut être considéré comme une information utile pour les futurs lecteurs.
Voici ma fonction pour réorganiser les facteurs d’un dataframe donné:
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) }
Usage: reorderFactors(df, "my_col", desired_level_order = c("how","I","want"))