web-dev-qa-db-fra.com

Remplacer <NA> dans une colonne de facteur

Je veux remplacer <NA> valeurs dans une colonne de facteurs avec une valeur valide. Mais je ne trouve pas de moyen. Cet exemple est uniquement à des fins de démonstration. Les données d'origine proviennent d'un fichier csv étranger que je dois traiter.

df <- data.frame(a=sample(0:10, size=10, replace=TRUE),
                 b=sample(20:30, size=10, replace=TRUE))
df[df$a==0,'a'] <- NA
df$a <- as.factor(df$a)

Pourrait ressembler à ceci

      a  b
1     1 29
2     2 23
3     3 23
4     3 22
5     4 28
6  <NA> 24
7     2 21
8     4 25
9  <NA> 29
10    3 24

Maintenant, je veux remplacer le <NA> valeurs avec un nombre.

df[is.na(df$a), 'a'] <- 88
In `[<-.factor`(`*tmp*`, iseq, value = c(88, 88)) :
  invalid factor level, NA generated

Je pense que j'ai manqué un concept R fondamental sur les facteurs. Suis-je? Je ne peux pas comprendre pourquoi cela ne fonctionne pas. Je pense invalid factor level signifie que 88 n'est pas un niveau valide dans ce facteur, non? Je dois donc dire à la colonne des facteurs qu'il existe un autre niveau?

17
buhtz

1) addNA Si fac est un facteur addNA(fac) est le même facteur mais avec NA ajouté comme niveau. Voir ?addNA

Pour forcer le niveau NA à 88:

facna <- addNA(fac)
levels(facna) <- c(levels(fac), 88)

donnant:

> facna
 [1] 1  2  3  3  4  88 2  4  88 3 
Levels: 1 2 3 4 88

1a) Ceci peut être écrit sur une seule ligne comme suit:

`levels<-`(addNA(fac), c(levels(fac), 88))

2) factor Cela peut aussi être fait sur une seule ligne en utilisant les différents arguments de factor comme ceci:

factor(fac, levels = levels(addNA(fac)), labels = c(levels(fac), 88), exclude = NULL)

2a) ou équivalent:

factor(fac, levels = c(levels(fac), NA), labels = c(levels(fac), 88), exclude = NULL)

) ifelse Une autre approche est:

factor(ifelse(is.na(fac), 88, paste(fac)), levels = c(levels(fac), 88))

4) forcats Le paquet forcats a une fonction pour cela:

library(forcats)

fct_explicit_na(fac, "88")
## [1] 1  2  3  3  4  88 2  4  88 3 
## Levels: 1 2 3 4 88

Remarque: Nous avons utilisé ce qui suit pour l'entrée fac

fac <- structure(c(1L, 2L, 3L, 3L, 4L, NA, 2L, 4L, NA, 3L), .Label = c("1", 
"2", "3", "4"), class = "factor")

Mise à jour: Ont amélioré (1) et ajouté (1a). Plus tard ajouté (4).

29
G. Grothendieck

Le problème est que NA n'est pas un niveau de ce facteur:

> levels(df$a)
[1] "2"  "4"  "5"  "9"  "10"

Vous ne pouvez pas le changer immédiatement, mais ce qui suit fera l'affaire:

df$a <- as.numeric(as.character(df$a))
df[is.na(df$a),1] <- 88
df$a <- as.factor(df$a)
> df$a
 [1] 9  88 3  9  5  9  88 8  3  9 
Levels: 3 5 8 9 88
> levels(df$a)
[1] "3"  "5"  "8"  "9"  "88"
4
000andy8484

une autre façon de faire est de:

#check levels
levels(df$a)
#[1] "3"  "4"  "7"  "9"  "10"

#add new factor level. i.e 88 in our example
df$a = factor(df$a, levels=c(levels(df$a), 88))

#convert all NA's to 88
df$a[is.na(df$a)] = 88

#check levels again
levels(df$a)
#[1] "3"  "4"  "7"  "9"  "10" "88"
4
Karim Kanatov

Le concept de base d'une variable de facteur est qu'elle ne peut prendre que des valeurs spécifiques, c'est-à-dire le levels. Une valeur qui n'est pas dans levels n'est pas valide.

Vous avez deux possibilités:

Si vous avez une variable qui suit ce concept, assurez-vous de définir tous les niveaux lorsque vous la créez, même ceux sans valeurs correspondantes.

Ou faites de la variable une variable de caractère et travaillez avec cela.

PS: Ces problèmes résultent souvent de l'importation de données. Par exemple, ce que vous y montrez devrait être une variable numérique et non une variable de facteur.

3
Roland