web-dev-qa-db-fra.com

Conversion de caractère en numérique sans contrainte NA dans R

Je travaille dans R et ai un dataframe, dd_2006, avec des vecteurs numériques. Lorsque j'ai importé les données pour la première fois, j'avais besoin de supprimer les $, les points décimaux et certains espaces de 3 de mes variables: SumOfCost, SumOfCases et SumOfUnits. Pour ce faire, j'ai utilisé str_replace_all. Cependant, une fois que j'ai utilisé str_replace_all, les vecteurs ont été convertis en caractères. J'ai donc utilisé as.numeric (var) pour convertir les vecteurs en numérique, mais les AN ont été introduits, même si, lorsque j'ai exécuté le code ci-dessous AVANT, le code as.numeric n'existait pas, il n'y avait pas d'AN dans les vecteurs.

sum(is.na(dd_2006$SumOfCost))
[1] 0
sum(is.na(dd_2006$SumOfCases))
[1] 0
sum(is.na(dd_2006$SumOfUnits))
[1] 0

Voici mon code après l'importation, en commençant par supprimer le $ du vecteur. Dans la sortie str(dd_2006), j'ai supprimé certaines variables pour des raisons d'espace. La colonne #s du code str_replace_all ci-dessous ne correspond donc pas à la sortie que j'ai publiée ici (mais dans le code d'origine):

library("stringr")
dd_2006$SumOfCost <- str_sub(dd_2006$SumOfCost, 2, ) #2=the first # after the $

#Removes decimal pt, zero's after, and commas
dd_2006[ ,9] <- str_replace_all(dd_2006[ ,9], ".00", "")
dd_2006[,9] <- str_replace_all(dd_2006[,9], ",", "")

dd_2006[ ,10] <- str_replace_all(dd_2006[ ,10], ".00", "")
dd_2006[ ,10] <- str_replace_all(dd_2006[,10], ",", "")

dd_2006[ ,11] <- str_replace_all(dd_2006[ ,11], ".00", "")
dd_2006[,11] <- str_replace_all(dd_2006[,11], ",", "")

str(dd_2006)
'data.frame':   12604 obs. of  14 variables:
 $ CMHSP                     : Factor w/ 46 levels "Allegan","AuSable Valley",..: 1 1 1
 $ FY                        : Factor w/ 1 level "2006": 1 1 1 1 1 1 1 1 1 1 ...
 $ Population                : Factor w/ 1 level "DD": 1 1 1 1 1 1 1 1 1 1 ...
 $ SumOfCases                : chr  "0" "1" "0" "0" ...
 $ SumOfUnits                : chr  "0" "365" "0" "0" ...
 $ SumOfCost                 : chr  "0" "96416" "0" "0" ...

J'ai trouvé une réponse à une question similaire au mien ici , en utilisant le code suivant:

# create dummy data.frame
d <- data.frame(char = letters[1:5], 
                fake_char = as.character(1:5), 
                fac = factor(1:5), 
                char_fac = factor(letters[1:5]), 
                num = 1:5, stringsAsFactors = FALSE)

Jetons un coup d'œil sur data.frame

> d
  char fake_char fac char_fac num
1    a         1   1        a   1
2    b         2   2        b   2
3    c         3   3        c   3
4    d         4   4        d   4
5    e         5   5        e   5

et laissez-nous courir:

> sapply(d, mode)
       char   fake_char         fac    char_fac         num 
"character" "character"   "numeric"   "numeric"   "numeric" 
> sapply(d, class)
       char   fake_char         fac    char_fac         num 
"character" "character"    "factor"    "factor"   "integer" 

Maintenant, vous vous demandez probablement "Où est une anomalie?" Eh bien, je me suis heurté à des choses assez étranges dans R, et ce n’est pas ce qui nous embarrasse le plus, mais cela peut vous dérouter, surtout si vous lisez ceci avant de vous coucher.

Voici: les deux premières colonnes sont des caractères. J'ai délibérément appelé 2nd one fake_char. Repérez la similarité de cette variable de caractère avec celle que Dirk a créée dans sa réponse. C'est en fait un vecteur numérique converti en caractère. Les 3ème et 4ème colonnes sont des facteurs, et la dernière est "purement" numérique.

Si vous utilisez la fonction de transformation, vous pouvez convertir le fake_char en numérique, mais pas la variable char.

> transform(d, char = as.numeric(char))
  char fake_char fac char_fac num
1   NA         1   1        a   1
2   NA         2   2        b   2
3   NA         3   3        c   3
4   NA         4   4        d   4
5   NA         5   5        e   5
Warning message:
In eval(expr, envir, enclos) : NAs introduced by coercion
but if you do same thing on fake_char and char_fac, you'll be lucky, and get away with no NA's:

transformer (d, fake_char = as.numeric (fake_char), char_fac = as.numeric (char_fac))

  char fake_char fac char_fac num
1    a         1   1        1   1
2    b         2   2        2   2
3    c         3   3        3   3
4    d         4   4        4   4
5    e         5   5        5   5

J'ai donc essayé le code ci-dessus dans mon script, mais j'ai quand même eu l'idée de NA (sans message d'avertissement sur la contrainte).

#changing sumofcases, cost, and units to numeric
dd_2006_1 <- transform(dd_2006, SumOfCases = as.numeric(SumOfCases), SumOfUnits = as.numeric(SumOfUnits), SumOfCost = as.numeric(SumOfCost))

> sum(is.na(dd_2006_1$SumOfCost))
[1] 12
> sum(is.na(dd_2006_1$SumOfCases))
[1] 7
> sum(is.na(dd_2006_1$SumOfUnits))
[1] 11

J'ai également utilisé table(dd_2006$SumOfCases) etc. pour examiner les observations et voir s'il y a des caractères que j'ai manqués dans les observations, mais il n'y en a pas. Avez-vous une idée de la raison pour laquelle les AN apparaissent et comment les éliminer? 

6
idemanalyst

Comme Anando l'a souligné, le problème se situe quelque part dans vos données et nous ne pouvons pas vraiment vous aider beaucoup sans un exemple reproductible. Cela dit, voici un extrait de code pour vous aider à identifier les enregistrements de vos données qui vous posent problème:

test = as.character(c(1,2,3,4,'M'))
v = as.numeric(test) # NAs intorduced by coercion
ix.na = is.na(v)
which(ix.na) # row index of our problem = 5
test[ix.na]  # shows the problematic record, "M"

Au lieu de deviner pourquoi les AN sont introduites, extrayez les enregistrements à l'origine du problème et corrigez-les directement/individuellement jusqu'à ce que les AN disparaissent.

UPDATE: On dirait que le problème vient de votre appel à str_replace_all. Je ne connais pas la bibliothèque stringr, mais je pense que vous pouvez accomplir la même chose avec gsub comme ceci:

v2 = c("1.00","2.00","3.00")
gsub("\\.00", "", v2)

[1] "1" "2" "3"

Je ne suis pas tout à fait sûr de ce que cela accomplit cependant:

sum(as.numeric(v2)!=as.numeric(gsub("\\.00", "", v2))) # Illustrate that vectors are equivalent.

[1] 0

À moins que cela ne vous permette de réaliser un objectif spécifique, je vous suggère de supprimer complètement cette étape du prétraitement, car elle ne semble pas nécessaire et semble vous poser problème.

13
David Marx

Si vous souhaitez également convertir le caractère en numérique, convertissez-le d'abord en facteur (à l'aide de as.factor) et enregistrez/écrasez la variable existante. Ensuite, convertissez cette variable factorielle en numérique (en utilisant as.numeric). De cette façon, vous ne créeriez pas d'AN et pourrez convertir le jeu de données que vous avez en numérique.

4
phoenix31_adv

Une solution simple consiste à laisser retype deviner de nouveaux types de données pour chaque colonne.

library(dplyr)
library(hablar)

dd_2006 %>% retype()
0
davsjob