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

StackOverflow https://stackoverflow.com/questions/1523126

  •  19-09-2019
  •  | 
  •  

Question

J'ai un fichier csv où certaines des valeurs numériques sont exprimées sous forme de chaînes par des virgules comme séparateur de milliers, par exemple "1,513" au lieu de 1513. Quelle est la façon la plus simple de lire les données en R?

Je peux utiliser read.csv(..., colClasses="character"), mais je dois dépouiller les virgules des éléments pertinents avant de convertir ces colonnes numériques, et je ne peux pas trouver une belle façon de le faire.

Était-ce utile?

La solution 3

Je veux utiliser R plutôt que pré-traitement des données car il rend plus facile lorsque les données sont révisées. Suite à la suggestion de Shane d'utiliser gsub, je pense que cela est à peu près aussi propre que je peux faire:

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

Autres conseils

Je ne sais pas comment avoir read.csv l'interpréter correctement, mais vous pouvez utiliser gsub pour remplacer "," avec "", puis convertir la chaîne en utilisant numeric as.numeric:

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

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

Vous pouvez pré-traiter le fichier, par exemple avec sed dans unix.

Vous pouvez avoir read.table ou read.csv faire cette conversion pour vous semi-automatique. Tout d'abord créer une nouvelle définition de la classe, puis créer une fonction de conversion et le définir comme un « comme » méthode utilisant la fonction SetAs comme ceci:

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

Ensuite, exécutez read.csv comme:

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

Cette question est de plusieurs années, mais je suis tombé sur elle, ce qui signifie peut-être d'autres le seront.

Le readr bibliothèque / package a quelques fonctionnalités intéressantes à elle. L'un d'eux est une belle façon d'interpréter des colonnes, comme ces « désordre ».

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 dans les fichiers: vous devez soit prétraiter, comme le commentaire ci-dessus concernant sed, ou vous devez traiter pendant la lecture . Souvent, si vous essayez de réparer les choses après le fait, il y a des hypothèses dangereuses faites qui sont difficiles à trouver. (Ce qui est pourquoi les fichiers plats sont si mauvais en premier lieu.)

Par exemple, si je ne l'avais pas signalé la col_types, je l'aurais obtenu 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 est maintenant un chr (character) au lieu d'un numeric.)

Ou, plus dangereusement, si elle était assez longtemps et la plupart des premiers éléments ne contenait pas des virgules:

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

(tels que les derniers éléments ressemblent:)

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

Ensuite, vous trouverez des difficultés à lire cette virgule du tout!

> 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. 

une solution de dplyr utilisant mutate_all et tuyaux

que vous avez les éléments suivants:

> 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 que vous voulez supprimer des virgules des variables de l'année x2014-X2016, et les convertir en numérique. , Disons-x2014 X2016 sont également lu comme les 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 fonction (s) à l'intérieur funs aux colonnes spécifiées

Je l'ai fait de façon séquentielle, une fonction à la fois (si vous utilisez plusieurs fonctions à l'intérieur funs vous créer des colonnes supplémentaires, inutiles)

"Preprocess" dans R:

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

Peut utiliser readLines sur un textConnection. Retirez ensuite seulement les virgules qui sont entre les chiffres:

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

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

Il est utile de savoir als mais pas directement pertinents à cette question que des virgules comme séparateur décimal peuvent être traités par read.csv2 (automagiquement) ou read.table (avec réglage de la « dec' paramètres).

Edit: Plus tard, je découvris comment utiliser colClasses en concevant une nouvelle classe. Voir:

Comment pour charger df 1000 avec séparateur dans R en tant que classe numérique?

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

Je pense que la pré-traitement est chemin à parcourir. Vous pouvez utiliser Notepad ++ qui a une expression régulière remplacer option.

Par exemple, si votre fichier était comme ceci:

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

Ensuite, vous pouvez utiliser le "([0-9]+),([0-9]+)" d'expression régulière et le 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.

Une façon très pratique est readr::read_delim familiale. Prenons l'exemple d'ici:    Importation csv avec plusieurs séparateurs en 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 se traduit par 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

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

locale = locale(decimal_mark = ",")

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

* Semicolon en deuxième ligne signifie que read_delim lira valeurs séparées par des virgules CSV.

Cela vous aidera à lire tous les numéros avec une virgule comme numéros appropriés.

Cordialement

Mateusz Kania

Nous pouvons également utiliser readr::parse_number, les colonnes doivent être des caractères bien. Si nous voulons l'appliquer pour plusieurs colonnes, nous pouvons boucle à travers des 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)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top