web-dev-qa-db-fra.com

Comment lire des données lorsque certains nombres contiennent des virgules comme séparateur de milliers?

J'ai un fichier CSV où certaines des valeurs numériques sont exprimées sous forme de chaînes 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 effacer les virgules des éléments pertinents avant de convertir ces colonnes en numériques, et je ne trouve pas de méthode élégante pour le faire.

103
Rob Hyndman

Je souhaite utiliser R plutôt que de prétraiter les données, car cela facilite la tâche lorsque les données sont révisées. Suivant la suggestion de Shane d’utiliser gsub, je pense que c’est aussi simple que possible:

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

Vous ne savez pas comment interpréter correctement read.csv, mais vous pouvez utiliser gsub pour remplacer "," par "", puis convertir la chaîne en numeric à l'aide de as.numeric:

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

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

Vous pouvez également prétraiter le fichier, par exemple avec sed sous unix.

125
Shane

Vous pouvez demander à read.table ou read.csv d'effectuer cette conversion semi-automatiquement pour vous. Commencez par créer une nouvelle définition de classe, puis créez une fonction de conversion et définissez-la en tant que méthode "en tant que" à l'aide de la fonction setAs comme suit:

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

Puis lancez read.csv comme ceci:

DF <- read.csv('your.file.here', 
   colClasses=c('num.with.commas','factor','character','numeric','num.with.commas'))
52
Greg Snow

Cette question a plusieurs années, mais je suis tombée dessus, ce qui signifie que d'autres le feront peut-être.

Le readr library/package a quelques fonctionnalités intéressantes. L’une d’elles est une bonne façon d’interpréter des colonnes «désordonnées», comme celles-ci.

library(readr)
read_csv("numbers\n800\n\"1,800\"\n\"3500\"\n6.5",
          col_types = list(col_numeric())
        )

Cela donne

Source: trame de données locale [4 x 1]

  numbers
    (dbl)
1   800.0
2  1800.0
3  3500.0
4     6.5

Un point important lors de la lecture de fichiers: vous devez soit pré-traiter, comme le commentaire ci-dessus concernant sed, soit vous devez traiter lors de la lecture. Souvent, si vous essayez de régler les problèmes après coup, vous faites certaines hypothèses dangereuses qui sont difficiles à trouver. (C'est pourquoi les fichiers plats sont si pervers en premier lieu.)

Par exemple, si je n'avais pas marqué le col_types, j'aurais eu ceci:

> read_csv("numbers\n800\n\"1,800\"\n\"3500\"\n6.5")
Source: local data frame [4 x 1]

  numbers
    (chr)
1     800
2   1,800
3    3500
4     6.5

(Notez qu'il s'agit maintenant d'une chr (character) au lieu d'une numeric.)

Ou, plus dangereusement, si elle était suffisamment longue et que la plupart des premiers éléments ne contenaient pas de virgule:

> set.seed(1)
> tmp <- as.character(sample(c(1:10), 100, replace=TRUE))
> tmp <- c(tmp, "1,003")
> tmp <- paste(tmp, collapse="\"\n\"")

(de sorte que les derniers éléments ressemblent :)

\"5\"\n\"9\"\n\"7\"\n\"1,003"

Ensuite, vous aurez du mal à lire cette virgule!

> tail(read_csv(tmp))
Source: local data frame [6 x 1]

     3"
  (dbl)
1 8.000
2 5.000
3 5.000
4 9.000
5 7.000
6 1.003
Warning message:
1 problems parsing literal data. See problems(...) for more details. 
11
Mike Williamson

"Prétraitement" dans R:

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

Peut utiliser readLines sur un textConnection. Ensuite, supprimez uniquement les virgules entre les 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, mais sans rapport direct avec 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 la définition du paramètre 'dec'). 

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

Comment charger df avec 1000 separator in R en tant que classe numérique?

6
42-

une solution dplyr utilisant mutate_all et des tubes

dites que vous avez ce qui suit:

> dft
Source: local data frame [11 x 5]

   Bureau.Name Account.Code   X2014   X2015   X2016
1       Senate          110 158,000 211,000 186,000
2       Senate          115       0       0       0
3       Senate          123  15,000  71,000  21,000
4       Senate          126   6,000  14,000   8,000
5       Senate          127 110,000 234,000 134,000
6       Senate          128 120,000 159,000 134,000
7       Senate          129       0       0       0
8       Senate          130 368,000 465,000 441,000
9       Senate          132       0       0       0
10      Senate          140       0       0       0
11      Senate          140       0       0       0

et voulez supprimer les virgules des variables d'année X2014-X2016 et les convertir en en numériques. de plus, disons que X2014-X2016 sont lus comme des facteurs (par défaut)

dft %>%
    mutate_all(funs(as.character(.)), X2014:X2016) %>%
    mutate_all(funs(gsub(",", "", .)), X2014:X2016) %>%
    mutate_all(funs(as.numeric(.)), X2014:X2016)

mutate_all applique la ou les fonctions à l'intérieur de funs aux colonnes spécifiées

Je l'ai fait séquentiellement, une fonction à la fois (si vous utilisez plusieurs fonctions Dans funs, vous créez des colonnes supplémentaires inutiles).

5
Paul

Si le numéro est séparé par "." et décimales par "," (1.200.000,00) en appelant gsub vous devez set fixed=TRUE as.numeric(gsub(".","",y,fixed=TRUE))

4
aca

Je pense que le prétraitement est la voie à suivre. Vous pouvez 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

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

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

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

2
Jacob

Un moyen très pratique est readr::read_delim- family. Prenons l'exemple d'ici: Importer csv avec plusieurs séparateurs dans R vous pouvez le faire comme suit:

txt <- 'OBJECTID,District_N,ZONE_CODE,COUNT,AREA,SUM
1,Bagamoyo,1,"136,227","8,514,187,500.000000000000000","352,678.813105723350000"
2,Bariadi,2,"88,350","5,521,875,000.000000000000000","526,307.288878142830000"
3,Chunya,3,"483,059","30,191,187,500.000000000000000","352,444.699742995200000"'

require(readr)
read_csv(txt) # = read_delim(txt, delim = ",")

Ce qui donne le résultat attendu:

# A tibble: 3 × 6
  OBJECTID District_N ZONE_CODE  COUNT        AREA      SUM
     <int>      <chr>     <int>  <dbl>       <dbl>    <dbl>
1        1   Bagamoyo         1 136227  8514187500 352678.8
2        2    Bariadi         2  88350  5521875000 526307.3
3        3     Chunya         3 483059 30191187500 352444.7
1
Rentrop

En utilisant la fonction read_delim, qui fait partie de readr library, vous pouvez spécifier un paramètre supplémentaire:

locale = locale(decimal_mark = ",")

read_delim("filetoread.csv", ';", locale = locale(decimal_mark = ","))

* Le point-virgule dans la deuxième ligne signifie que read_delim lira les valeurs séparées par un point-virgule au format CSV.

Cela vous aidera à lire tous les chiffres avec une virgule.

Cordialement

Mateusz Kania

0
Mateusz Kania

Nous pouvons également utiliser readr::parse_number, les colonnes doivent cependant être des caractères. Si nous voulons l'appliquer à plusieurs colonnes, nous pouvons parcourir les colonnes en utilisant lapply

df[2:3] <- lapply(df[2:3], readr::parse_number)
df

#  a        b        c
#1 a    12234       12
#2 b      123  1234123
#3 c     1234     1234
#4 d 13456234    15342
#5 e    12312 12334512

Ou utilisez mutate_at de dplyr pour l'appliquer à des variables spécifiques.

library(dplyr)
df %>% mutate_at(2:3, readr::parse_number)
#Or
df %>% mutate_at(vars(b:c), readr::parse_number)

données

df <- data.frame(a = letters[1:5], 
                 b = c("12,234", "123", "1,234", "13,456,234", "123,12"),
                 c = c("12", "1,234,123","1234", "15,342", "123,345,12"), 
                 stringsAsFactors = FALSE)
0
Ronak Shah

Ce n'est pas aussi compliqué, essayez ceci: Y <- as.numeric (gsub (",", "", as.character (y))) peut le sous-définir avec y $ 2 comme indiqué y $ 2 <- as.numeric (gsub (",", "", as.character (y $ 2)))

0
Colonelxy

Une autre solution:

 y <- c("1,200","20,000","100","12,111") 

 as.numeric(unlist(lapply( strsplit(y,","),paste, collapse="")))

Cependant, il sera considérablement plus lent que gsub

0
liujx80