Question Comment convertir un facteur en nombre entier \ numeric sans perte d'information?


Lorsque je convertis un facteur en nombre ou en nombre entier, j'obtiens les codes de niveau sous-jacents et non les valeurs sous forme de 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 vraies valeurs:

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 un meilleur moyen de convertir un facteur en numérique?


466
2017-08-05 18:53


origine


Réponses:


Voir la section Avertissement de ?factor:

En particulier, as.numeric appliqué à   un facteur est dénué de sens, et peut   se produire par coercition implicite. À   transformer un facteur f à   approximativement son original 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 est-ce as.numeric(levels(f))[f] plus efficace que as.numeric(as.character(f))?

as.numeric(as.character(f)) est effectivement as.numeric(levels(f)[f]), donc vous effectuez la conversion en numérique sur length(x) valeurs, plutôt que sur nlevels(x) valeurs. La différence de vitesse sera plus apparente 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. Quelle que soit la conversion effectuée, il est peu probable que cette opération soit le goulot d'étranglement de votre code, alors ne vous inquiétez pas trop à ce sujet.


Quelques horaires

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

550
2017-08-05 19:01



R possède 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 agaçant, il n'y a rien pour gérer le facteur -> numérique conversion. Comme une extension de la réponse de Joshua Ulrich, je suggérerais de surmonter cette omission avec 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 mieux encore dans votre .Rprofile fichier.


68
2018-03-27 23:39



Le moyen le plus simple serait d'utiliser unfactor fonction de paquet manche

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"

20
2017-12-01 14:11



Chaque réponse dans ce post n'a pas réussi à générer des résultats pour moi, NA 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 ne pas pour convertir des facteurs numériques en valeurs numériques, il s'agit de convertir des facteurs catégoriels en leurs nombres de niveau correspondants.


12
2018-02-22 18:26



C'est possible seulement dans le cas où les étiquettes de facteur correspondent aux valeurs d'origine. Je vais l'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 avec le type double, f est avec type entier. C'est la première perte d'information inévitable. Les facteurs sont toujours stockés sous forme d'entiers.

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

2) Il n'est pas possible de revenir aux valeurs d'origine (10, 20, 30, 40) ayant seulement f disponible. On peut voir ça f ne contient que 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, il faut connaître les valeurs des niveaux utilisés pour créer le facteur. Dans ce cas c(10, 20, 30, 40). Si nous connaissons les niveaux d'origine (dans le bon ordre), nous pouvons revenir aux valeurs d'origine.

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

Et cela ne fonctionnera que si les étiquettes ont été définies pour toutes les valeurs possibles dans les données d'origine.

Donc, si vous avez besoin des valeurs d'origine, vous devez les conserver. Sinon, il y a de fortes chances qu'il ne soit pas possible de les contacter uniquement par un facteur.


7
2017-10-09 12:34