2017-05-24 1 views
2

ProblèmeConvertir des variables de caractère numérique, mais à l'exclusion d'une variable de caractères

Travailler avec une trame de données en R, je souhaite modifier les variables représentées sous forme de caractères dans les variables représentées sous forme de nombres (ie de la classe chr-num).

Pour un ensemble de données complet, c'est un problème simple (saveurs différentes de solutions here, here, here et here). Cependant, j'ai une variable qui doit rester en tant que caractères.

Exemple de données

En utilisant cet exemple des données (df), disons que je veux changer seulement var1 de la classe chr-num, laissant "chrOK" comme une variable chr. Dans mon jeu de données réel, il y a beaucoup de variables à changer, donc les approches manuelles comme df$var1 = as.numeric(df$var1) sont trop laborieuses.

df = data.frame(var1 = c("1","2","3","4"), 
       var2 = c(1,2,3,4), 
       chrOK = c("rick", "summer","beth", "morty"), 
       stringsAsFactors = FALSE) 

str(df) 

'data.frame': 4 obs. of 3 variables: 
$ var1 : chr "1" "2" "3" "4" 
$ var2 : num 1 2 3 4 
$ chrOK: chr "rick" "summer" "beth" "morty" 

Solutions partielles

J'ai essayé plusieurs approches qui semblent proches, mais ne font pas exactement ce que je veux.

Tentative 1 - introduit NAs

La plupart de mes colonnes sont des caractères qui doivent être numériques, comme "var1". Donc, en utilisant apply() pour convertir les travaux de classe. Cependant, cette approche échoue induit NA valeurs dans "chrOK".

df = as.data.frame(apply(df, 2, function(x) as.numeric(x))) 

Warning message: 
In FUN(newX[, i], ...) : NAs introduced by coercion 

str(df) 
'data.frame': 4 obs. of 3 variables: 
$ var1 : num 1 2 3 4 
$ var2 : num 1 2 3 4 
$ chrOK: num NA NA NA NA 

Tentative 2 - split, convertir, cbind

En utilisant apply() sur le sous-ensemble de chr les variables, à l'exclusion "chrOK", ne provoque pas NA s, mais nécessite l'utilisation cbind() de re-inclure "chrOK".

Cette solution n'est pas idéale car les résultats cbind() sont difficiles à vérifier pour les mutations de données. (De plus, "chrOK" est retourné comme un facteur utilisant df = cbind(changed,as.character(unchanged)) ne fonctionne pas [a]..)

changed = as.data.frame(apply(df[-(which(colnames(df)=="chrOK"))],2,function(x) as.numeric(x))) 
unchanged = (df$chrOK) 

df = cbind(changed,unchanged) 

str(df) 
'data.frame': 4 obs. of 3 variables: 
$ var1  : num 1 2 3 4 
$ var2  : num 1 2 3 4 
$ unchanged: Factor w/ 4 levels "beth","morty",..: 3 4 1 2 #[a] 

Tentative 3 - sous-ensemble correct, mais l'erreur lors de la conversion

En utilisant setdiff() je reçois le sous-ensemble de chr variables de classe excluant `" chrOK ".

df[setdiff(names(df[sapply(df,is.character)]),"chrOK")] 
    var1 
1 1 
2 2 
3 3 
4 4 

Mais en essayant de le brancher dans une fonction de transformation, de sorte que seul le sous-ensemble est modifié chr-num renvoie une erreur (voir [b]).

apply(as.numeric(df[setdiff(names(df[sapply(df,is.character)]),"chrOK")]), 
     2,function(x) as.numeric(x)) 

Error in apply(as.numeric(df[setdiff(names(df[sapply(df, is.character)]), : 
(list) object cannot be coerced to type 'double' #[b] 

Questions

  • Quelle est la meilleure solution pour convertir une variables de caractère de trame de données numérique, tout en excluant un sous-ensemble spécifié?
  • Laquelle de mes tentatives est le bon chemin ou y at-il une meilleure approche?
  • [bonus] Quel mécanisme provoque les résultats inattendus en [a] et [b], ci-dessus?

Répondre

1

Nous pouvons utiliser type.convert de base R en boucle sur les colonnes de l'ensemble de données et de l'assigner à l'objet d'origine

df[] <- lapply(df, function(x) type.convert(as.character(x), as.is = TRUE)) 
str(df) 
#'data.frame': 4 obs. of 3 variables: 
#$ var1 : int 1 2 3 4 
#$ var2 : int 1 2 3 4 
#$ chrOK: chr "rick" "summer" "beth" "morty" 

Le type.convert appelle un code C ie C_typeconvert


La raison pour laquelle les solutions OP obtiennent des NA est

1) apply convertit le data.frame en matrix et matrix ne peut contenir qu'un seul class. Supposons qu'il existe un seul élément character dans le matrix, il convertit le tout en character.

2) L'utilisation de as.numeric avec apply est problématique car le 'chrOK' est déjà une colonne de classe character. Chaque fois que as.numeric est appliqué à des chaînes non numériques, il le convertit en NA.

3) L'OP a utilisé le même apply dans la deuxième méthode. Il est décrit en 1.

+0

Cela fonctionne! Comment cela "sait" changer var1 mais pas chrOK? – Danielle

+0

@Danielle Le 'type.convert' appelle un code C interne et il vérifie si les éléments sont des nombres ou des caractères avant de les convertir en classes respectives. – akrun

+0

@Danielle Merci pour les commentaires. Vous pouvez également vérifier [ici] (https://stackoverflow.com/help/someone-answers) – akrun