Confusión entre niveles de factor y etiquetas de factor

106

Parece haber una diferencia entre los niveles y las etiquetas de un factor en R. Hasta ahora, siempre pensé que los niveles eran el nombre 'real' de los niveles de los factores, y las etiquetas eran los nombres utilizados para la salida (como tablas y gráficos) . Evidentemente, este no es el caso, como muestra el siguiente ejemplo:

df <- data.frame(v=c(1,2,3),f=c('a','b','c'))
str(df)
'data.frame':   3 obs. of  2 variables:
 $ v: num  1 2 3
 $ f: Factor w/ 3 levels "a","b","c": 1 2 3

df$f <- factor(df$f, levels=c('a','b','c'),
  labels=c('Treatment A: XYZ','Treatment B: YZX','Treatment C: ZYX'))
levels(df$f)
[1] "Treatment A: XYZ" "Treatment B: YZX" "Treatment C: ZYX"

Pensé que todavía se podía acceder a los niveles ('a', 'b', 'c') al realizar un script, pero esto no funciona:

> df$f=='a'
[1] FALSE FALSE FALSE

Pero esto hace:

> df$f=='Treatment A: XYZ' 
[1]  TRUE FALSE FALSE

Entonces, mi pregunta consta de dos partes:

  • ¿Cuál es la diferencia entre niveles y etiquetas?

  • ¿Es posible tener diferentes nombres para los niveles de factores para la creación de scripts y la salida?

Antecedentes: para scripts más largos, la creación de scripts con niveles de factor cortos parece ser mucho más fácil. Sin embargo, para informes y gráficos, estos niveles de factor cortos pueden no ser adecuados y deben reemplazarse por nombres más precisos.

donodarazao
fuente

Respuestas:

131

Muy breve: los niveles son la entrada, las etiquetas son la salida en la factor()función. Un factor tiene solo un levelatributo, que se establece mediante el labelsargumento en la factor()función. Esto es diferente del concepto de etiquetas en paquetes estadísticos como SPSS y puede resultar confuso al principio.

Qué haces en esta línea de código

df$f <- factor(df$f, levels=c('a','b','c'),
  labels=c('Treatment A: XYZ','Treatment B: YZX','Treatment C: ZYX'))

le está diciendo a R que hay un vector df$f

  • que quieres transformar en un factor,
  • en el que los diferentes niveles se codifican como a, byc
  • y para los que desea que los niveles se etiqueten como Tratamiento A, etc.

La función de factor buscará los valores a, byc, los convertirá en clases de factores numéricos y agregará los valores de la etiqueta al levelatributo del factor. Este atributo se utiliza para convertir los valores numéricos internos a las etiquetas correctas. Pero como ve, no hay ningún labelatributo.

> df <- data.frame(v=c(1,2,3),f=c('a','b','c'))    
> attributes(df$f)
$levels
[1] "a" "b" "c"

$class
[1] "factor"

> df$f <- factor(df$f, levels=c('a','b','c'),
+   labels=c('Treatment A: XYZ','Treatment B: YZX','Treatment C: ZYX'))    
> attributes(df$f)
$levels
[1] "Treatment A: XYZ" "Treatment B: YZX" "Treatment C: ZYX"

$class
[1] "factor"
Joris Meys
fuente
1
¡Gracias por la rápida respuesta! Supongo que ahora entiendo el propósito de los niveles y las etiquetas. ¿Quizás alguna sugerencia para hacer que la salida sea humanamente mejor legible sin editar manualmente los nombres de las tablas y las leyendas de la trama?
donodarazao
6
A menudo transformaba los niveles justo antes de trazar / crear etiquetas, por ejemplo, mantenía los niveles como "a", "b", "c" mientras manipulaba, luego usaba niveles (f) <- paste ("Tratamiento", toupper (niveles ( f)), sep = "") [o algo] al trazar. O cree un factor paralelo f_pretty que lleve consigo y use solo para la salida ...
Ben Bolker
Pensé en ambos, pero ambos métodos tienen desventajas. El primero puede resultar tedioso al trazar una gran cantidad de gráficos, y el segundo puede volverse tedioso cuando se involucra mucha agregación de datos en la creación de scripts. Pero aparentemente no hay forma de evitarlo fácilmente, así que seguiré tus sugerencias. :)
donodarazao
@ 42- No sé a qué te refieres con "valores numéricos". Si te refieres a los valores internos en el factor, eso es exactamente lo que dije anteriormente. De ahí la mención de valores numéricos internos . Si especifica el levelsargumento, proporciona los valores en la entrada que deben coincidir con el labelsargumento. R mantiene las etiquetas (como el atributo levels, y existe la confusión) y almacena códigos enteros internamente. Estos códigos enteros no tienen nada que ver con los valores originales, sea del tipo que sean. Creo que me has malentendido.
Joris Meys
Disculpas Lo que escribiste también fue mi entendimiento, y ahora que estoy releyendo tu pregunta, no puedo ver dónde pensé que dijiste de otra manera. Eliminaré mi comentario porque agrega menos que nada.
IRTFM
17

Escribí un paquete "lfactors" que te permite hacer referencia a niveles o etiquetas.

# packages
install.packages("lfactors")
require(lfactors)

flips <- lfactor(c(0,1,1,0,0,1), levels=0:1, labels=c("Tails", "Heads"))
# Tails can now be referred to as, "Tails" or 0
# These two lines return the same result
flips == "Tails"
#[1]  TRUE FALSE FALSE  TRUE  TRUE FALSE
flips == 0 
#[1]  TRUE FALSE FALSE  TRUE  TRUE FALSE

Tenga en cuenta que un factor requiere que los niveles sean numéricos para que no se puedan confundir con las etiquetas.

pdb
fuente
3
Este es un buen paquete y gracias por publicarlo (y escribirlo). Parece el tipo de funcionalidad que debería ser nativa de los factores R; es bueno ver un paquete que proporciona este tipo de mapeo de pares nombre-valor con comprobaciones de equivalencia integradas.
Soren