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.
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))})
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.
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'))
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.
"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?
dplyr
utilisant mutate_all
et des tubesdites 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).
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))
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.
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
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
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)
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)))
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
.