web-dev-qa-db-fra.com

Ajouter un niveau supplémentaire aux facteurs dans le cadre de données

J'ai un cadre de données avec des colonnes de facteurs numériques et ordonnées. J'ai beaucoup de valeurs NA, donc aucun niveau ne leur est assigné. J'ai changé NA en "Pas de réponse", mais les niveaux des colonnes de facteurs ne contiennent pas ce niveau. Voici comment j'ai commencé, mais je ne sais pas comment le terminer de manière élégante:

addNoAnswer = function(df) {
   factorOrNot = sapply(df, is.factor)
   levelsList = lapply(df[, factorOrNot], levels)
   levelsList = lapply(levelsList, function(x) c(x, "No Answer"))
   ...

Existe-t-il un moyen d'appliquer directement de nouveaux niveaux à des colonnes de facteur, par exemple, par exemple:

df[, factorOrNot] = lapply(df[, factorOrNot], factor, levelsList)

Bien sûr, cela ne fonctionne pas correctement. 

Je veux que l'ordre des niveaux soit préservé et que le niveau "Pas de réponse" soit ajouté à la dernière place.

20
enedene

Vous pouvez définir une fonction qui ajoute les niveaux à un facteur, mais ne renvoie rien d'autre:

addNoAnswer <- function(x){
  if(is.factor(x)) return(factor(x, levels=c(levels(x), "No Answer")))
  return(x)
}

Ensuite, vous venez lapply cette fonction à vos colonnes

df <- as.data.frame(lapply(df, addNoAnswer))

Cela devrait retourner ce que vous voulez.

25
ilir

La fonction levels accepte l'appel levels(x) <- value. Par conséquent, il est très facile d'ajouter différents niveaux:

f1 <- factor(c("a", "a", NA, NA, "b", NA, "a", "c", "a", "c", "b"))
str(f1)
 Factor w/ 3 levels "a","b","c": 1 1 NA NA 2 NA 1 3 1 3 ...
levels(f1) <- c(levels(f1),"No Answer")
f1[is.na(f1)] <- "No Answer"
str(f1)
 Factor w/ 4 levels "a","b","c","No Answer": 1 1 4 4 2 4 1 3 1 3 ...

Vous pouvez ensuite le boucler autour de toutes les variables dans un data.frame:

f1 <- factor(c("a", "a", NA, NA, "b", NA, "a", "c", "a", "c", "b"))
f2 <- factor(c("c", NA, "b", NA, "b", NA, "c" ,"a", "d", "a", "b"))
f3 <- factor(c(NA, "b", NA, "b", NA, NA, "c", NA, "d" , "e", "a"))
df1 <- data.frame(f1,n1=1:11,f2,f3)

str(df1)
  'data.frame':   11 obs. of  4 variables:
  $ f1: Factor w/ 3 levels "a","b","c": 1 1 NA NA 2 NA 1 3 1 3 ...
  $ n1: int  1 2 3 4 5 6 7 8 9 10 ...
  $ f2: Factor w/ 4 levels "a","b","c","d": 3 NA 2 NA 2 NA 3 1 4 1 ...
  $ f3: Factor w/ 5 levels "a","b","c","d",..: NA 2 NA 2 NA NA 3 NA 4 5 ...    

for(i in 1:ncol(df1)) if(is.factor(df1[,i])) levels(df1[,i]) <- c(levels(df1[,i]),"No Answer")
df1[is.na(df1)] <- "No Answer"

str(df1)
 'data.frame':   11 obs. of  4 variables:
  $ f1: Factor w/ 4 levels "a","b","c","No Answer": 1 1 4 4 2 4 1 3 1 3 ...
  $ n1: int  1 2 3 4 5 6 7 8 9 10 ...
  $ f2: Factor w/ 5 levels "a","b","c","d",..: 3 5 2 5 2 5 3 1 4 1 ...
  $ f3: Factor w/ 6 levels "a","b","c","d",..: 6 2 6 2 6 6 3 6 4 5 ...
19
Bastien

En développant la réponse de ilir et son commentaire, vous pouvez vérifier si une colonne est un facteur et si elle ne contient pas déjà le nouveau niveau, puis ajoutez le niveau et rendez ainsi la fonction ré-exécutable:

addLevel <- function(x, newlevel=NULL) {
  if(is.factor(x)) {
    if (is.na(match(newlevel, levels(x))))
      return(factor(x, levels=c(levels(x), newlevel)))
  }
  return(x)
}

Vous pouvez ensuite l'appliquer comme ceci:

dataFrame$column <- addLevel(dataFrame$column, "newLevel")
3
Danny Varod

Depuis la dernière réponse à cette question, cela est devenu possible en utilisant fct_explicit_na() à partir du paquet forcats. J'ajoute ici l'exemple donné dans la documentation.

f1 <- factor(c("a", "a", NA, NA, "a", "b", NA, "c", "a", "c", "b"))
table(f1)

# f1
# a b c 
# 4 2 2 

f2 <- forcats::fct_explicit_na(f1)
table(f2)

# f2
#     a         b         c (Missing) 
#     4         2         2         3 

La valeur par défaut est (Missing), mais cela peut être modifié via l'argument na_level.

3
Joe

Vous devez convertir la colonne en caractère, puis ajouter le nouveau niveau en fonction de la condition, puis enfin convertir la colonne en facteur.

Étapes 1.Premier convertisseur de colonne de facteur en caractère:

        df$column2 <- as.character(column2)

2.Ajouter le nouveau niveau

        df[df$column1=="XYZ",]column2 <- "new_level"

3. Convertir pour factoriser à nouveau

        df$column2 <- as.factor(df$column2)
1
vpathak

J'ai une réponse très simple qui peut ne pas répondre directement à votre scénario spécifique, mais constitue un moyen simple de le faire en général

levels(df$column) <- c(levels(df$column), newFactorLevel)
0
Michael LaScaleia

Pour les facteurs, les niveaux sont les valeurs numériques attribuées à chaque valeur unique de la variable de facteur. L'avantage d'utiliser des facteurs est que les variables catégorielles sont meilleures pour les visualisations. La valeur d'origine de la variable factorielle est stockée sous forme de caractère, même s'il s'agit d'un nombre. Donc, pour récupérer la valeur originale, utilisez d’abord la conversion as.character - elle renverra les valeurs de facteur, pas les numéros de niveau qui commencent par zéro. Une fois que vous avez défini la valeur du format de caractère, utilisez as.numeric pour obtenir la valeur numérique d'origine.

df $ factor_var a des valeurs numériques stockées sous forme de caractères

factor_var.values ​​= as.numeric (as.character (df $ factor_var))

0
Shobha Mourya