134 votes

Comment lire des données lorsque certains chiffres contiennent des virgules en tant que séparateur de milliers?

J'ai un fichier csv où certaines des valeurs numériques sont exprimées en tant que chaînes de caractères avec des virgules comme séparateur de milliers, par exemple "1,513" au lieu de 1513. Quel est le moyen le plus simple de lire les données dans R?

Je peux utiliser read.csv(..., colClasses="character"), mais ensuite je dois supprimer les virgules des éléments concernés avant de convertir ces colonnes en valeurs numériques, et je ne trouve pas de moyen simple de le faire.

151voto

Shane Points 40885

Ne sachant pas comment faire en sorte que read.csv l'interprète correctement, mais vous pouvez utiliser sub pour remplacer "," par "", puis convertir la chaîne en numérique en utilisant as.numeric :

y <- c("1,200","20,000","100","12,111")
as.numeric(gsub(",", "", y))
# [1]  1200 20000 100 12111

Cela a également été répondu précédemment sur R-Help (et dans Q2 ici).

Alternativement, vous pouvez prétraiter le fichier, par exemple avec sed dans unix.

0 votes

Je suppose qu'en ayant ces chiffres, nous traiterons presque exclusivement avec des entiers - donc je pense que l'utilisation de as.integer pourrait être le meilleur choix dans la plupart des cas?

67voto

Greg Snow Points 22040

Vous pouvez utiliser read.table ou read.csv pour effectuer cette conversion de manière semi-automatique. Créez d'abord une nouvelle définition de classe, puis créez une fonction de conversion et définissez-la comme une méthode "as" en utilisant la fonction setAs de la manière suivante :

setClass("num.with.commas")
setAs("character", "num.with.commas", 
        function(from) as.numeric(gsub(",", "", from) ) )

Ensuite, exécutez read.csv comme suit :

DF <- read.csv('votre.fichier.ici', 
   colClasses=c('num.with.commas','factor','character','numeric','num.with.commas'))

3 votes

C'est une astuce très utile. Elle pourrait être utilisée pour la conversion à l'importation (par exemple, convertir des valeurs O/N en vecteur logique en utilisant setAs("character", "logical.Y.N", function(from) c(Y=TRUE,N=FALSE)[from])).

1 votes

Le même tour est utilisé dans problème similaire. Et à ajouter : on pourrait utiliser soit setClass("num.with.commas") ou suppresMessage(setAs(.....)) pour éviter le message sur la classe manquante.

0 votes

Salut Greg, merci d'avoir partagé cette fonction très utile. Lors de l'exécution, je reçois le message d'avertissement suivant : dans la méthode pour 'coerce' avec la signature '"character","num.with.commas"' : aucune définition pour la classe "num.with.commas" Aurais-tu une idée de ce qui pourrait poser problème ici, j'ai ton code mot pour mot?

19voto

Rob Hyndman Points 10068

Je veux utiliser R plutôt que de prétraiter les données car cela facilite les révisions ultérieures des données. Suivant la suggestion de Shane d'utiliser gsub, je pense que c'est à peu près aussi propre que je puisse le faire :

x <- read.csv("file.csv",header=TRUE,colClasses="character")
col2cvt <- 15:41
x[,col2cvt] <- lapply(x[,col2cvt],function(x){as.numeric(gsub(",", "", x))})

0 votes

Ne colClasses="char" force-t-il pas toutes les colonnes à être char dans ce cas les autres à part 15:41 sont également char? Peut-être laisser read.csv() décider et ensuite convertir celles qui sont dans les colonnes 15:41 peut vous donner 'plus' de colonnes numériques.

0 votes

Oui, mais comme l'a noté ma question, toutes les autres colonnes sont des caractères. Je pourrais utiliser as.is=TRUE à la place, ce qui serait plus général. Mais laisser read.csv() décider en utilisant les arguments par défaut n'est pas utile car il convertira tout ce qui ressemble à un caractère en facteur, ce qui pose des problèmes pour les colonnes numériques car elles ne se convertissent pas correctement en utilisant as.numeric().

0 votes

Vous devriez envisager de définir l'argument dec= dans la table de lecture à ".". C'est la valeur par défaut pour read.csv2, mais la virgule est intégrée en dur dans read.csv().

6voto

BondedDust Points 105234

"Preprocess" en R:

lines <- "www, rrr, 1,234, ttt \n rrr,zzz, 1,234,567,987, rrr"

Peut utiliser readLines sur une textConnection. Ensuite, supprimer uniquement les virgules qui se trouvent entre des chiffres:

gsub("([0-9]+)\\,([0-9])", "\\1\\2", lines)

## [1] "www, rrr, 1234, ttt \n rrr,zzz, 1234567987, rrr"

Il est également utile de savoir, bien que ce ne soit pas directement pertinent pour cette question, que les virgules en tant que séparateurs décimaux peuvent être gérées par read.csv2 (automatiquement) ou read.table (avec le paramètre 'dec' paramètré).

Édition: Plus tard, j'ai découvert comment utiliser colClasses en concevant une nouvelle classe. Voir:

Comment charger un df avec un séparateur de milliers en R en tant que classe numérique?

0 votes

Merci, c'était un bon pointeur mais cela ne fonctionne pas pour les chiffres qui contiennent plusieurs marques décimales, par exemple 1,234,567.89 - j'ai dû contourner ce problème pour importer une feuille de calcul Google dans R, voir stackoverflow.com/a/30020171/3096626 pour une fonction simple qui fait le travail pour plusieurs marques décimales

0voto

Jacob Points 22306

Je pense que le prétraitement est la meilleure option. Vous pourriez utiliser Notepad++ qui dispose d'une option de remplacement d'expression régulière.

Par exemple, si votre fichier était comme ceci :

"1,234","123","1,234"
"234","123","1,234"
123,456,789

Alors, vous pourriez utiliser l'expression régulière "([0-9]+),([0-9]+)" et le remplacer par \1\2

1234,"123",1234
"234","123",1234
123,456,789

Ensuite, vous pourriez utiliser x <- read.csv(file="x.csv",header=FALSE) pour lire le fichier.

23 votes

Tout ce que vous pouvez scripter, vous devriez le faire. Le faire manuellement introduit la possibilité d'erreur, ainsi que de ne pas être très reproductible.

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