Come convertire un fattore in intero-numerico senza perdita di informazioni?

Quando converto un fattore in un numerico o intero, ottengo i codici di livello sottostanti, non i valori come numeri.

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

Devo ricorrere al paste per ottenere i valori reali:

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

C'è un modo migliore per convertire un fattore in numerico?

Soluzione

Vedi la sezione Warning di ?factor:

In particolare, as.numeric applicato a

un fattore è privo di significato, e può avvenire per coercizione implicita. Per trasformare un fattore f in circa i suoi valori numerici originali valori, as.numeric(levels(f))[f] è raccomandato e leggermente più efficiente di as.numeric(as.character(f)).

Le FAQ su R hanno un consiglio simile.


**Perché as.numeric(levels(f))[f]è più efficace di as.numeric(as.character(f))?

as.numeric(as.character(f))è effettivamente as.numeric(levels(f)[f]), quindi state eseguendo la conversione in numerico sui valori di length(x), piuttosto che sui valori di nlevels(x). La differenza di velocità sarà più evidente per vettori lunghi con pochi livelli. Se i valori sono per lo più unici, non ci sarà molta differenza di velocità. Comunque tu faccia la conversione, è improbabile che questa operazione sia il collo di bottiglia del tuo codice, quindi non preoccupartene troppo.


Alcuni tempi

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
Commentari (6)

R ha un certo numero di funzioni (non documentate) per convertire i fattori:

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

Ma fastidiosamente, non c'è nulla per gestire la conversione fattore -> numerico. Come estensione della risposta di Joshua Ulrich, suggerirei di superare questa omissione con la definizione di una propria funzione idiomatica:


as.numeric.factor 
Commentari (6)

È possibile solo nel caso in cui le etichette dei fattori corrispondano ai valori originali. Lo spiego con un esempio.

Supponiamo che i dati siano il vettore x:


x 
Commentari (0)