J'ai un bloc de données avec des variables numériques et des variables catégoriques factor
. L'ordre des niveaux pour ces facteurs n'est pas ce que je veux qu'ils soient.
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 alors un non-sens total).
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 level. Ainsi, 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 levels
de 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
un peu plus, juste pour l'enregistrement
## 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 R Lexicon, est de ne changer que leslabelspour une variable de facteur donnée (c.-à-d., laissez les données ainsi que le facteur niveaux, inchangées).
df$letters = factor(df$letters, labels=c("d", "c", "b", "a"))
étant donné que vous souhaitez modifier uniquement le mappage datapoint-to-label et non les données ou le schéma factoriel (comment les points de données sont-ils regroupés dans des groupes individuels ou des valeurs factorielles, il peut être utile de savoir comment le mappage est défini à l'origine lorsque vous créez le facteur pour la première fois.
les règles sont simples:
Traiter avec les facteurs dans R est un travail assez particulier, je dois l'avouer ... Pendant que vous réorganisez les niveaux de facteurs, 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 changez que de niveau (qui dirait, non?), 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 levels
puis essayez de la relier avec factor
. Ne le fais pas !!! Faire ne pas utilisez levels
ou vous fouillerez les choses (à moins que vous ne sachiez exactement ce que vous faites).
Une petite suggestion: évitez de nommer vos objets avec un nom identique à celui de R (df
est une fonction de densité pour la distribution F, letters
donne des lettres de l'alphabet minuscule). Dans ce cas particulier, votre code ne serait pas défectueux, mais il peut parfois l'ê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 ceci (je vais recommencer depuis le début):
> 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
Notez que vous pouvez également vous nommer data.frame
avec df
et letters
au lieu de g
et le résultat sera OK. En réalité, ce code est identique à celui que vous avez posté, seuls les noms sont changés. Cette partie factor(dtf$letter, levels = letters[4:1])
ne génère pas d'erreur, mais elle peut être déconcertante!
Lisez attentivement le manuel ?factor
! Quelle est la différence entre factor(g, levels = letters[4:1])
et factor(g, labels = letters[4:1])
? Qu'est-ce qui est similaire dans levels(g) <- letters[4:1]
et g <- factor(g, labels = letters[4:1])
?
Vous pouvez utiliser la syntaxe ggplot pour que nous puissions vous aider davantage sur celui-ci!
À votre santé!!!
Modifier:
ggplot2
nécessite en réalité de changer les niveaux et les valeurs? Hm ... je vais creuser celui-ci ...
Depuis que cette question était active, Hadley a publié son nouveau paquet forcats
pour manipuler les facteurs et je le trouve scandaleusement utile. Exemples tirés 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 ajouter plus de niveaux:
fct_expand(df$letters, "e") %>% levels
# [1] "a" "b" "c" "d" "e"
Et bien d'autres fonctions fct_xxx()
utiles.
Je souhaite ajouter un autre cas où les niveaux pourraient être des chaînes portant des chiffres accompagnés de caractères spéciaux: 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 facteurs en fonction de la valeur numérique, sans écrire explicitement les niveaux, nous pouvons 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'une image donnée:
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"))