Como converter um fator para inteiro \ numérico sem perda de informação?

Quando eu converto um fator para um numérico ou inteiro, eu 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 

Eu tenho que recorrer a paste 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 fator em numérico?

Veja a seção Aviso do ?factor

Em particular, como o as.numeric aplicado a um fator não tem sentido, e pode acontecer por coerção implícita. Para transformar um fator f em aproximadamente seus valores numéricos originais, as.numeric(levels(f))[f] é recomendado e um pouco mais eficiente que as.numeric(as.character(f)) .

O FAQ em R tem conselhos semelhantes .


Por que é as.numeric(levels(f))[f] mais eficiente 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 valores numéricos length(x) numéricos, ao invés de valores nlevels(x) . A diferença de velocidade será mais aparente para vetores longos com poucos níveis. Se os valores forem exclusivos, não haverá muita diferença na velocidade. No entanto, você faz a conversão, essa operação provavelmente não será o gargalo no seu código, entã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 várias funções de conveniência (não documentadas) para converter fatores:

  • as.character.factor
  • as.data.frame.factor
  • as.Date.factor
  • as.list.factor
  • as.vector.factor

Mas irritantemente, não há nada para lidar com o fator -> conversão numérica . Como extensão da resposta de Joshua Ulrich, sugiro superar essa omissão com a definição de sua própria function idiomática:

 as.numeric.factor < - function(x) {as.numeric(levels(x))[x]} 

que você pode armazenar no início do seu script, ou melhor ainda, no seu arquivo .Rprofile .

A maneira mais fácil seria usar a function unfactor do pacote varhandle

 unfactor(your_factor_variable) 

Este exemplo pode ser um começo rápido:

 x < - rep(c("a", "b", "c"), 20) y <- rep(c(1, 1, 0), 20) class(x) # -> "character" class(y) # -> "numeric" x < - factor(x) y <- factor(y) class(x) # -> "factor" class(y) # -> "factor" library(varhandle) x < - unfactor(x) y <- unfactor(y) class(x) # -> "character" class(y) # -> "numeric" 

Todas as respostas neste post falharam em gerar resultados para mim, as NAs foram geradas.

 y2< -factor(c("A","B","C","D","A")); as.numeric(levels(y2))[y2] [1] NA NA NA NA NA Warning message: NAs introduced by coercion 

O que funcionou para mim é isso

 as.integer(y2) # [1] 1 2 3 4 1 

Nota: essa resposta em particular não é para converter fatores numéricos em valores numéricos, é converter fatores categóricos em seus números de níveis correspondentes.

É possível apenas no caso em que os marcadores de fator correspondam aos valores originais. Vou explicar isso com um exemplo.

Suponha que os dados sejam vetor x :

 x < - c(20, 10, 30, 20, 10, 40, 10, 40) 

Agora vou criar um fator com quatro labels:

 f < - factor(x, levels = c(10, 20, 30, 40), labels = c("A", "B", "C", "D")) 

1) x é com o tipo double, f é com o tipo integer. Esta é a primeira perda inevitável de informações. Os fatores são sempre armazenados como números inteiros.

 > typeof(x) [1] "double" > typeof(f) [1] "integer" 

2) Não é possível reverter para os valores originais (10, 20, 30, 40) tendo apenas f disponível. Podemos ver que f contém apenas valores inteiros 1, 2, 3, 4 e dois atributos - a lista de labels ("A", "B", "C", "D") e o atributo de class "fator". 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 reverter aos valores originais, precisamos conhecer os valores dos níveis usados ​​na criação do fator. Neste caso c(10, 20, 30, 40) . Se soubermos os níveis originais (na ordem correta), poderemos voltar aos valores originais.

 > orig_levels < - c(10, 20, 30, 40) > x1 < - orig_levels[f] > all.equal(x, x1) [1] TRUE 

E isso funcionará apenas no caso de os labels terem sido definidos para todos os valores possíveis nos dados originais.

Então, se você precisar dos valores originais, você precisa mantê-los. Caso contrário, há uma grande chance de não ser possível voltar a eles apenas por um fator.