2010-03-03 19 views
93

Tengo marco de datos con algunas variables numéricas y algunas variables categóricas factor. El orden de los niveles para esos factores no es la forma en que quiero que sean.Reordenar niveles de un factor sin cambiar el orden de los valores

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 cambio el orden de los niveles, las letras ya no están con sus números correspondientes (mis datos es un disparate total a partir de este punto en adelante).

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

I simplemente quieren cambiar el nivel de orden , así que cuando el trazado, las barras se muestran en el orden deseado - que puede diferir del orden alfabético por defecto.

Respuesta

102

utilizar el argumento 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 
+1

Gracias, esto funcionó. Por alguna extraña razón, ahora ggplot ha cambiado correctamente el orden en la leyenda, pero no en la trama. Extraño. – crangos

+7

ggplot2 me requirió cambiar ambos, el orden de los niveles (ver arriba) y el orden de los valores del marco de datos. df <- df [nrow (df): 1,] # reverse – crangos

7

así lo desea, en I léxico, es cambiar sólo las etiquetas para una variable factor dado (es decir, dejar los datos, así como el factor de niveles, sin cambios).

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

dado que desea cambiar sólo el -punto de datos a la etiqueta de mapeo y no los datos o el esquema de los factores (cómo los puntos de datos se han agrupado en los contenedores o los valores de los factores individuales, podría ayudar a saber cómo . el mapeo se establece originalmente cuando se crea inicialmente el factor

las reglas son simples:

  • etiquetas se asignan a niveles por valor de índice (es decir, el valor a niveles [2] se le da la etiqueta laboratorio el [2]);
  • niveles de factor se pueden establecer explícitamente pasándolos a través del niveles argumento; o
  • si ningún valor se suministra para el argumento niveles, el valor predeterminado se usa que es el resultado de llamar único en el vector de datos aprobada en (para los datos argumento);
  • las etiquetas pueden establecerse explícitamente a través del argumento labels; o
  • si ningún valor se suministra para el argumento de etiquetas, el valor por defecto es usadas que sólo los niveles vector
+1

No sé por qué esto no está tan votado como la respuesta aceptada. Esto es mucho más informativo. – Rambatino

+7

Si usa este enfoque, sus datos estarán mal etiquetados. – Nazer

+0

@Nazer gracias, solucionado – rawr

19

poco más , solo para el registro

## 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]) 

Usted puede así que encuentre útil Relevel y combine_factor.

+2

Tu primera respuesta no funciona para mí. Pero esto funciona: 'reordenar (df $ letters, seq (4,1))' –

+0

Tengo una situación muy extraña donde el orden 'funciona en un conjunto de datos, no en otro. En el otro conjunto de datos, arroja un error "Error en la aplicación (X = X, INDEX = x, FUN = FUN, ...): falta el argumento" X ", sin valor predeterminado". No estoy seguro de cuál es la solución a este problema. No puedo encontrar ninguna diferencia relevante entre los conjuntos de datos. – Deleet

5

Manejar los factores en R es un trabajo bastante peculiar, debo admitir ... Al reordenar los niveles de factores, no se están reordenando los valores numéricos subyacentes.He aquí una pequeña demostración:

> 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" 

Ahora, si convierte a este factor numérico, obtendrá:

# 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 

Como se puede ver ... al cambiar los niveles, sólo puede cambiarse niveles (¿Quién diría, eh?), ¡no los valores numéricos! Pero cuando se usa la función factor como @Jonathan Chang sugirió, sucede algo diferente: usted mismo cambia los valores numéricos.

Obtiene el error una vez más porque hace levels y luego intenta volver a aumentarlo con factor. ¡No lo hagas! Haga no use levels o ensuciará las cosas (a menos que sepa exactamente lo que está haciendo).

Una sugerencia lil': evitar nombrar los objetos con un nombre idéntico como objetos de R (df es función de densidad para la distribución F, letters da letras del alfabeto en minúsculas). En este caso particular, su código no sería defectuoso, pero a veces puede ser ... pero esto puede crear confusión, y no queremos eso, ¿verdad? =)

su lugar, utilice algo como esto (voy a ir desde el principio una vez más):

> 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 

en cuenta que también se puede nombrar data.frame con df y letters en lugar de g, y el resultado estará bien. En realidad, este código es idéntico al que publicaste, solo cambian los nombres. Esta parte factor(dtf$letter, levels = letters[4:1]) no arrojaría un error, ¡pero puede ser confuso!

leer el manual ?factor a fondo! ¿Cuál es la diferencia entre factor(g, levels = letters[4:1]) y factor(g, labels = letters[4:1])? ¿Qué es similar en levels(g) <- letters[4:1] y g <- factor(g, labels = letters[4:1])?

Puedes poner la sintaxis de ggplot, ¡así podemos ayudarte más en esto!

¡Salud!

Editar:

ggplot2 requiere realmente para cambiar ambos niveles y valores? Hm ... Voy a desenterrar este ...

2

Desde que esta pregunta fue activa por última vez Hadley ha lanzado su nuevo paquete forcats para manipular factores y me resulta escandalosamente útil. Ejemplos de trama de datos del OP:

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

para revertir los niveles:

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

Para añadir más niveles:

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

Y muchos más útiles fct_xxx() funciones.

+0

¿Esto todavía está disponible? –

+1

Claro, vea [aquí] (https://blog.rstudio.org/2016/08/31/forcats-0-1-0/). – Joe

+0

Desea escribir un código como este: 'df%>% mutate (letters = fct_rev (letters))'. – jazzurro

2

Deseo agregar otro caso en el que los niveles podrían ser cadenas que llevan los números alongwith algunos caracteres especiales: al igual que por debajo ejemplo

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

Los niveles predeterminados de x es:

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

Aquí si quiere reordenar los niveles de factor de acuerdo con el valor numérico, sin escribir explícitamente los niveles, lo que podríamos hacer es

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 

Espero que esto se pueda considerar como información útil para futuros lectores.

Cuestiones relacionadas