Cómo convertir un factor de número entero \ numérico sin pérdida de información?

StackOverflow https://stackoverflow.com/questions/3418128

  •  26-09-2019
  •  | 
  •  

Pregunta

Cuando convierto un factor a un valor numérico o entero, consigo los códigos de nivel subyacentes, no los 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

Tengo que recurrir a paste para obtener los valores reales:

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

¿Hay una mejor manera de convertir un factor a numérico?

¿Fue útil?

Solución

Vea la sección de Advertencia de ?factor :

  

En particular, as.numeric aplica a   un factor no tiene sentido, y puede   ocurrir por la coerción implícita. A   transformar un factor a f   aproximadamente su numérico originales   valores, as.numeric(levels(f))[f] es   recomendado y un poco más   eficientes que las   as.numeric(as.character(f)).

El FAQ en R tiene un consejo similar .


¿Por qué es más eficiente que as.numeric(levels(f))[f] as.numeric(as.character(f))?

as.numeric(as.character(f)) es efectivamente as.numeric(levels(f)[f]), por lo que está realizando la conversión a los valores numéricos en length(x), en lugar de en los valores nlevels(x). La diferencia de velocidad será más evidente por largos vectores con pocos niveles. Si los valores son en su mayoría único, no habrá mucha diferencia en la velocidad. Sin embargo lo hace la conversión, esta operación es poco probable que sea el cuello de botella en el código, por lo que no se preocupe demasiado acerca de él.


Algunos tiempos

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

Otros consejos

R tiene un número de funciones de confort (sin papeles) para los factores de conversión:

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

Pero molesto, no hay nada para manejar el factor -> numérico conversión. Como una extensión de la respuesta de Joshua Ulrich, sugeriría para superar esta omisión con la definición de su propia función idiomática:

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

que se puede almacenar en el comienzo de la secuencia de comandos, o incluso mejor en su .Rprofile archivo.

La forma más fácil sería utilizar la función unfactor del paquete varhandle

unfactor(your_factor_variable)

Este ejemplo puede ser un comienzo 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"

Nota:. Esta respuesta particular es no para la conversión de factores con valores numéricos a valores numéricos, corresponde a la conversión de factores categóricos para sus números de nivel correspondientes


Cada respuesta en este post no ha podido generar resultados para mí, AN se estaban generando.

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

Lo que funcionó para mí es esto -

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

Es posible Sólo en el caso de que las etiquetas de los factores coinciden con los valores originales. Voy a explicarlo con un ejemplo.

Suponga los datos es vector x:

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

Ahora creará un factor con cuatro etiquetas:

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

1) x es con el tipo doble, f es con tipo entero. Esta es la primera pérdida inevitable de información. Factores siempre se almacenan como números enteros.

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

2) No es posible volver a los valores originales (10, 20, 30, 40) que tiene solamente f disponible. Podemos ver que f tiene solamente valores enteros 1, 2, 3, 4 y dos atributos - la lista de etiquetas ( "A", "B", "C", "D") y el atributo de clase de "factor". Nada más.

> 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 volver a los valores originales que tenemos que conocer los valores de los niveles utilizados en la creación del factor. En este caso c(10, 20, 30, 40). Si conocemos los niveles originales (en el orden correcto), podemos volver a los valores originales.

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

Y esto funcionará sólo en el caso cuando las etiquetas se han definido para todos los valores posibles de los datos originales.

Así que si va a necesitar los valores originales, hay que mantenerlos. De lo contrario, existe una alta probabilidad de que no será posible volver a ellos sólo de un factor.

Se puede utilizar hablar::convert si tiene una trama de datos. La sintaxis es fácil:

Muestra df

library(hablar)
library(dplyr)

df <- dplyr::tibble(a = as.factor(c("7", "3")),
                    b = as.factor(c("1.5", "6.3")))

Solución

df %>% 
  convert(num(a, b))

le da:

# A tibble: 2 x 2
      a     b
  <dbl> <dbl>
1    7.  1.50
2    3.  6.30

O si quieres una columna a ser entero y uno numérico:

df %>% 
  convert(int(a),
          num(b))

resultados en:

# A tibble: 2 x 2
      a     b
  <int> <dbl>
1     7  1.50
2     3  6.30

tarde al juego, accidentalmente, me encontré con trimws() puede convertir a factor(3:5) c("3","4","5"). A continuación, puede llamar as.numeric(). Es decir:

as.numeric(trimws(x_factor_var))
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top