Comment lire les données lorsque certains numéros contiennent des virgules comme séparateur de milliers?
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.
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)