50 votes

Comment concaténer des facteurs, sans qu'ils soient convertis au niveau des entiers ?

J'ai été surpris de voir que R va convertir les facteurs en un nombre lors de la concaténation de vecteurs. Cela se produit même lorsque les niveaux sont les mêmes. Par exemple :

> facs <- as.factor(c("i", "want", "to", "be", "a", "factor", "not", "an", "integer"))
> facs
[1] i       want    to      be      a       factor  not     an      integer
Levels: a an be factor i integer not to want
> c(facs[1 : 3], facs[4 : 5])
[1] 5 9 8 3 1

Quelle est la manière idiomatique de faire cela dans R (dans mon cas, ces vecteurs peuvent être assez grands) ? Merci.

39voto

fgregg Points 558

Desde el R Liste de diffusion :

unlist(list(facs[1 : 3], facs[4 : 5]))

Pour "lier" les facteurs, faites

data.frame(facs[1 : 3], facs[4 : 5])

10voto

Richie Cotton Points 35365

Une autre solution consiste à convertir le facteur en vecteur de caractères, puis à le reconvertir lorsque vous avez fini de concaténer.

cfacs <- as.character(facs)
x <- c(cfacs[1:3], cfacs[4:5]) 

# Now choose between
factor(x)
# and
factor(x, levels = levels(facs))

8voto

Connor Harris Points 241

Utilice fct_c de la forcats (qui fait partie du tidyverse ).

> library(forcats)
> facs <- as.factor(c("i", "want", "to", "be", "a", "factor", "not", "an", "integer"))
> fct_c(facs[1:3], facs[4:5])
[1] i    want to   be   a
Levels: a an be factor i integer not to want

fct_c n'est pas dupe des concaténations de facteurs avec des codages numériques discordants :

> x <- as.factor(c('c', 'z'))
> x
[1] c z
Levels: c z
> y <- as.factor(c('a', 'b', 'z'))
> y
[1] a b z
Levels: a b z
> c(x, y)
[1] 1 2 1 2 3
> fct_c(x, y)
[1] c z a b z
Levels: c z a b
> as.numeric(fct_c(x, y))
[1] 1 2 3 4 2

6voto

Aniko Points 7555

Wow, je n'avais jamais réalisé que ça faisait ça. Voici un moyen de contourner le problème :

x <- c(facs[1 : 3], facs[4 : 5]) 
x <- factor(x, levels=1:nlevels(facs), labels=levels(facs))
x

Avec la sortie :

[1] i    want to   be   a   
Levels: a an be factor i integer not to want

Cela ne fonctionnera que si les deux vecteurs ont les mêmes niveaux qu'ici.

4voto

Paul Johson Points 1

C'est un très mauvais R gotcha. Dans le même ordre d'idée, en voici un qui vient d'avaler plusieurs heures de mon temps.

x <- factor(c("Yes","Yes","No", "No", "Yes", "No"))
y <- c("Yes", x)

> y
[1] "Yes" "2"   "2"   "1"   "1"   "2"   "1"  
> is.factor(y)
[1] FALSE

Il me semble que la meilleure solution est celle de Richie, qui contraint au caractère.

> y <- c("Yes", as.character(x))
> y
[1] "Yes" "Yes" "Yes" "No"  "No"  "Yes" "No" 
> y <- as.factor(y)
> y
[1] Yes Yes Yes No  No  Yes No 
Levels: No Yes

Tant que vous réglez les niveaux correctement, comme le mentionne Richie.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X