Quando converto um fator para um numérico ou inteiro, recebo os códigos de nível subjacentes, não os valores como números.
f <- factor(sample(runif(5), 20, replace = TRUE))
## [1] 0.0248644019011408 0.0248644019011408 0.179684827337041
## [4] 0.0284090070053935 0.363644931698218 0.363644931698218
## [7] 0.179684827337041 0.249704354675487 0.249704354675487
## [10] 0.0248644019011408 0.249704354675487 0.0284090070053935
## [13] 0.179684827337041 0.0248644019011408 0.179684827337041
## [16] 0.363644931698218 0.249704354675487 0.363644931698218
## [19] 0.179684827337041 0.0284090070053935
## 5 Levels: 0.0248644019011408 0.0284090070053935 ... 0.363644931698218
as.numeric(f)
## [1] 1 1 3 2 5 5 3 4 4 1 4 2 3 1 3 5 4 5 3 2
as.integer(f)
## [1] 1 1 3 2 5 5 3 4 4 1 4 2 3 1 3 5 4 5 3 2
Tenho de recorrer à "pasta" para obter os valores reais:
as.numeric(paste(f))
## [1] 0.02486440 0.02486440 0.17968483 0.02840901 0.36364493 0.36364493
## [7] 0.17968483 0.24970435 0.24970435 0.02486440 0.24970435 0.02840901
## [13] 0.17968483 0.02486440 0.17968483 0.36364493 0.24970435 0.36364493
## [19] 0.17968483 0.02840901
Existe uma maneira melhor de converter um factor em numérico?
Veja a seção Aviso de ?fator
:
Em particular, 'as.numeric' aplicado a um fator é insignificante, e pode acontece por coerção implícita. Para transformar um fator
f
em aproximadamente seu numero original valores,as.numeric(levels(f))[f]
é recomendado e um pouco mais eficiente do queas.numeric(as.character(f))
.
A FAQ sobre R tem conselhos semelhantes.
Porque é as.numeric(levels(f))[f]
mais eficaz do que as.numeric(as.character(f))
?
as.numeric(as.character(f))
é efetivamente as.numeric(levels(f)[f])
, então você está realizando a conversão para numérico em length(x)
valores, ao invés de em nlevels(x)
valores. A diferença de velocidade será mais aparente para vetores longos com poucos níveis. Se os valores são na maioria das vezes únicos, haverá uma grande diferença na velocidade. Entretanto você faz a conversão, esta operação é improvável que seja o gargalo no seu código, então não'não se preocupe muito com isso.
**alguns horários***
library(microbenchmark)
microbenchmark(
as.numeric(levels(f))[f],
as.numeric(levels(f)[f]),
as.numeric(as.character(f)),
paste0(x),
paste(x),
times = 1e5
)
## Unit: microseconds
## expr min lq mean median uq max neval
## as.numeric(levels(f))[f] 3.982 5.120 6.088624 5.405 5.974 1981.418 1e+05
## as.numeric(levels(f)[f]) 5.973 7.111 8.352032 7.396 8.250 4256.380 1e+05
## as.numeric(as.character(f)) 6.827 8.249 9.628264 8.534 9.671 1983.694 1e+05
## paste0(x) 7.964 9.387 11.026351 9.956 10.810 2911.257 1e+05
## paste(x) 7.965 9.387 11.127308 9.956 11.093 2419.458 1e+05
R tem uma série de funções de conveniência (não documentadas) para a conversão de fatores:
as.character.factor
as.list.factor
Mas irritantemente, não há nada para lidar com o factor -> conversão numérica. Como uma extensão da resposta de Joshua Ulrich's, eu sugeriria superar esta omissão com a definição da sua própria função idiomática:
as.numeric.factor <- function(x) {as.numeric(levels(x))[x]}
que você pode armazenar no início do seu script, ou ainda melhor no seu arquivo .Rprofile
.
É possível **somente*** no caso em que as etiquetas dos factores coincidam com os valores originais. Vou explicar isso com um exemplo.
Suponha que os dados são vetoriais x
:
x <- c(20, 10, 30, 20, 10, 40, 10, 40)
Agora vou criar um factor com quatro etiquetas:
f <- factor(x, levels = c(10, 20, 30, 40), labels = c("A", "B", "C", "D"))
x
é com tipo duplo, f
é com tipo inteiro. Esta é a primeira perda inevitável de informação. Os fatores são sempre armazenados como números inteiros.> typeof(x)
[1] "double"
> typeof(f)
[1] "integer"
f
disponível. Podemos ver que `f' contém apenas valores inteiros 1, 2, 3, 4 e dois atributos - a lista de etiquetas ("A", "B", "C", "D") e o atributo de classe "factor". Nada mais.> str(f)
Factor w/ 4 levels "A","B","C","D": 2 1 3 2 1 4 1 4
> attributes(f)
$levels
[1] "A" "B" "C" "D"
$class
[1] "factor"
Para voltarmos aos valores originais temos de conhecer os valores dos níveis utilizados na criação do factor. Neste caso, c(10, 20, 30, 40)
. Se conhecermos os níveis originais (na ordem correta), podemos retornar aos valores originais.
> orig_levels <- c(10, 20, 30, 40)
> x1 <- orig_levels[f]
> all.equal(x, x1)
[1] TRUE
E isto só funcionará no caso de terem sido definidas etiquetas para todos os valores possíveis nos dados originais.
Por isso, se você vai precisar dos valores originais, você tem que mantê-los. Caso contrário, há uma grande chance de não ser possível voltar a eles apenas por um fator.