Comment convertir un facteur en entiernumérique sans perte d'information?

quand je convertis un facteur à un numérique ou un entier, je reçois les codes de niveau sous-jacents, pas les valeurs en tant que nombres.

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

je dois recourir à paste pour obtenir les valeurs réelles:

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

y a-t-il une meilleure façon de convertir un facteur en numérique?

477
demandé sur Jaap 2010-08-05 22:53:32

5 réponses

voir la section Avertissement de ?factor :

en particulier, as.numeric appliqué à un facteur de sens, et peut arriver par la coercition implicite. De transformer un facteur f environ son origine numérique valeurs, as.numeric(levels(f))[f] est recommandé et légèrement plus efficace que as.numeric(as.character(f)) .

la FAQ sur R a des conseils similaires .


pourquoi as.numeric(levels(f))[f] est-il plus efficace que as.numeric(as.character(f)) ?

as.numeric(as.character(f)) est effectivement as.numeric(levels(f)[f]) , si vous effectuez la conversion en numérique sur length(x) valeurs", plutôt que sur les nlevels(x) valeurs". La différence de vitesse sera la plus évidente pour les vecteurs longs avec peu de niveaux. Si les valeurs sont pour la plupart uniques, il n'y aura pas beaucoup de différence de vitesse. Cependant vous faire la conversion, cette opération est peu probable d'être le goulot d'étranglement dans votre code, donc ne vous inquiétez pas trop à ce sujet.


quelques minuteries

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
571
répondu Joshua Ulrich 2016-01-17 07:51:48

r a un certain nombre de fonctions de commodité (non documentées) pour convertir les facteurs:

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

mais il n'y a rien pour gérer la conversion facteur -> numérique . Comme dans le prolongement de la réponse de Joshua Ulrich, je suggérerais de surmonter cette omission par la définition de votre propre fonction idiomatique:

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

que vous pouvez stocker au début de votre script, ou encore mieux dans votre fichier .Rprofile .

68
répondu Jealie 2014-06-04 18:19:53

la façon la plus facile serait d'utiliser unfactor fonction du paquet varhandle

unfactor(your_factor_variable)

cet exemple peut être un démarrage rapide:

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"
21
répondu Mehrad Mahmoudian 2016-01-25 09:14:08

chaque réponse dans ce post n'a pas réussi à générer des résultats pour moi , NAs ont été générés.

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

ce qui a fonctionné pour moi est ceci -

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

Note: Cette réponse particulière est et non . pour convertir les facteurs à valeur numérique en facteurs numériques, il s'agit de convertir les facteurs catégoriques en leurs numéros de niveau correspondants.

13
répondu Indi 2018-06-01 15:13:52

il est possible seulement dans le cas où les étiquettes de facteur correspondent aux valeurs originales. Je vais vous expliquer avec un exemple.

supposons que les données sont un vecteur x :

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

maintenant je vais créer un facteur avec quatre étiquettes:

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

1) x est de type double, f est de type entier. C'est la première perte d'information inévitable. Facteur sont toujours stockés comme des entiers.

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

2) Il n'est pas possible de revenir aux valeurs initiales (10, 20, 30, 40) avec seulement f disponible. Nous pouvons voir que f contient seulement les valeurs entières 1, 2, 3, 4 et deux attributs - la liste des étiquettes ("A", "B", "C", "D") et l'attribut de classe "facteur". Rien de plus.

> 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"

Pour revenir aux valeurs d'origine, nous devons connaître les valeurs de niveaux utilisés dans la création de ce facteur. Dans ce cas c(10, 20, 30, 40) . Si nous connaissons les niveaux originaux (dans le bon ordre), nous pouvons revenir aux valeurs originales.

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

et cela ne fonctionnera que dans le cas où des étiquettes ont été définies pour toutes les valeurs possibles dans les données originales.

donc si vous avez besoin des valeurs originales, vous devez les garder. Dans le cas contraire, il y a de fortes chances qu'il ne soit pas possible d'y revenir uniquement à partir d'un facteur.

7
répondu djhurio 2015-10-09 12:34:35