Confusão entre níveis de fator e rótulos de fator

106

Parece haver uma diferença entre os níveis e os rótulos de um fator em R. Até agora, sempre pensei que os níveis eram o nome 'real' dos níveis dos fatores e os rótulos eram os nomes usados ​​para a saída (como tabelas e gráficos) . Obviamente, este não é o caso, como mostra o exemplo a seguir:

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"

Achei que os níveis ('a', 'b', 'c') ainda poderiam ser acessados ​​durante o script, mas isso não funciona:

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

Mas isso faz:

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

Então, minha pergunta consiste em duas partes:

  • Qual é a diferença entre níveis e rótulos?

  • É possível ter nomes diferentes para níveis de fator para script e saída?

Histórico: para scripts mais longos, a criação de scripts com níveis de fator curtos parece ser muito mais fácil. No entanto, para relatórios e gráficos, esses níveis curtos de fator podem não ser adequados e devem ser substituídos por nomes mais precisos.

donodarazao
fonte

Respostas:

131

Muito breve: os níveis são a entrada, os rótulos são a saída da factor()função. Um fator possui apenas um levelatributo, que é definido pelo labelsargumento na factor()função. Isso é diferente do conceito de rótulos em pacotes estatísticos como o SPSS e pode ser confuso no início.

O que você faz nesta linha de código

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

está dizendo a R que há um vetor df$f

  • que você deseja transformar em um fator,
  • em que os diferentes níveis são codificados como a, b e c
  • e para os quais você deseja que os níveis sejam rotulados como Tratamento A etc.

A função de fator irá procurar os valores a, bec, convertê-los em classes de fator numéricas e adicionar os valores de rótulo ao levelatributo do fator. Este atributo é usado para converter os valores numéricos internos para os rótulos corretos. Mas, como você vê, não há 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
fonte
1
Obrigado pela resposta rápida! Acho que agora entendo o propósito dos níveis e rótulos. Talvez alguma sugestão para tornar a saída humanamente mais legível sem editar manualmente os nomes das tabelas e legendas de plotagem?
donodarazao
6
Eu costumava transformar os níveis logo antes de plotar / criar rótulos, por exemplo, manter os níveis como "a", "b", "c" enquanto manipulava e, em seguida, usar os níveis (f) <- colar ("Tratamento", toupper (níveis ( f)), sep = "") [ou algo] durante a plotagem. Ou crie um fator paralelo f_pretty que você carrega e usa apenas para a saída ...
Ben Bolker
Pensei em ambos, mas ambos os métodos têm desvantagens. O primeiro pode ser enfadonho ao plotar um grande número de gráficos e o segundo pode se tornar enfadonho quando uma grande quantidade de agregação de dados está envolvida no script. Mas, aparentemente, não há como evitar isso facilmente, então vou seguir suas sugestões. :)
donodarazao
@ 42- Não tenho certeza do que você quer dizer com "valores numéricos". Se você se refere aos valores internos do fator, é exatamente o que eu disse acima. Daí a menção de valores numéricos internos . Se você especificar o levelsargumento, fornecerá os valores na entrada que devem corresponder ao labelsargumento. R mantém os rótulos (como o atributo levels, e aí está a confusão) e armazena códigos inteiros internamente. Esses códigos inteiros não têm nada a ver com os valores originais, qualquer que seja o tipo. Eu acho que você me entendeu mal.
Joris Meys
Desculpas. O que você escreveu foi meu entendimento também, e agora que estou relendo sua pergunta, não consigo ver onde pensei que você disse de outra forma. Vou deletar meu comentário porque adiciona menos do que nada.
IRTFM
17

Eu escrevi um pacote "lfactors" que permite que você se refira a níveis ou rótulos.

# 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

Observe que um lfactor requer que os níveis sejam numéricos para que não possam ser confundidos com os rótulos.

PDB
fonte
3
este é um bom pacote e obrigado por postar sobre ele (e por escrever). Parece o tipo de funcionalidade que deveria ser nativa para fatores R - bom ver um pacote que fornece esse tipo de mapeamento de par nome-valor com verificações de equivalência integradas.
Soren