Como ler dados quando alguns números contêm vírgulas como separador de milhar?
Pergunta
Eu tenho um arquivo csv onde alguns dos valores numéricos são expressos como strings com vírgulas como separador de milhar, por exemplo. "1,513"
em vez de 1513
.Qual é a maneira mais simples de ler os dados em R?
Eu posso usar read.csv(..., colClasses="character")
, mas preciso retirar as vírgulas dos elementos relevantes antes de converter essas colunas em numérico e não consigo encontrar uma maneira legal de fazer isso.
Solução 3
Quero usar R em vez de pré-processar os dados, pois facilita a revisão dos dados.Seguindo a sugestão de Shane de usar gsub
, acho que isso é o mais legal que posso fazer:
x <- read.csv("file.csv",header=TRUE,colClasses="character")
col2cvt <- 15:41
x[,col2cvt] <- lapply(x[,col2cvt],function(x){as.numeric(gsub(",", "", x))})
Outras dicas
Não tenho certeza sobre como ter read.csv
interprete -o corretamente, mas você pode usar gsub
para substituir ","
com ""
, e depois converter a string para numeric
usando as.numeric
:
y <- c("1,200","20,000","100","12,111")
as.numeric(gsub(",", "", y))
# [1] 1200 20000 100 12111
Isso foi Também respondeu anteriormente no R-Help (e em Q2 aqui).
Como alternativa, você pode pré-processar o arquivo, por exemplo com sed
em Unix.
Você pode ter lido.table ou read.csv fazer essa conversão para você semi-automaticamente. Primeiro, crie uma nova definição de classe, depois crie uma função de conversão e defina -a como um método "AS" usando a função Setas como assim:
setClass("num.with.commas")
setAs("character", "num.with.commas",
function(from) as.numeric(gsub(",", "", from) ) )
Em seguida, execute read.csv como:
DF <- read.csv('your.file.here',
colClasses=c('num.with.commas','factor','character','numeric','num.with.commas'))
Esta pergunta tem vários anos, mas eu tropecei nela, o que significa que talvez outros o façam.
o readr
A biblioteca / pacote possui alguns bons recursos. Uma delas é uma boa maneira de interpretar colunas "bagunçadas", como essas.
library(readr)
read_csv("numbers\n800\n\"1,800\"\n\"3500\"\n6.5",
col_types = list(col_numeric())
)
Isso rende
Fonte: quadro de dados local [4 x 1
numbers
(dbl)
1 800.0
2 1800.0
3 3500.0
4 6.5
Um ponto importante ao ler em arquivos: você precisa pré-processar, como o comentário acima sed
, ou você tem que processar enquanto lê. Freqüentemente, se você tentar consertar as coisas após o fato, há algumas suposições perigosas feitas que são difíceis de encontrar. (É por isso que os arquivos planos são tão maus em primeiro lugar.)
Por exemplo, se eu não tivesse sinalizado o col_types
, Eu teria conseguido o seguinte:
> 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
(Observe que agora é um chr
(character
) em vez de um numeric
.)
Ou, mais perigosamente, se fosse longo e a maioria dos primeiros elementos não continha vírgulas:
> set.seed(1)
> tmp <- as.character(sample(c(1:10), 100, replace=TRUE))
> tmp <- c(tmp, "1,003")
> tmp <- paste(tmp, collapse="\"\n\"")
(de modo que os últimos elementos parecem :)
\"5\"\n\"9\"\n\"7\"\n\"1,003"
Então você encontrará problemas para ler essa vírgula!
> 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.
a dplyr
solução usando mutate_all
e tubos
diga que você tem o seguinte:
> 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
e deseja remover vírgulas das variáveis do ano x2014-x2016 e convertê-las em numéricas.Além disso, digamos x2014-x2016 são lidos como fatores (padrão)
dft %>%
mutate_all(funs(as.character(.)), X2014:X2016) %>%
mutate_all(funs(gsub(",", "", .)), X2014:X2016) %>%
mutate_all(funs(as.numeric(.)), X2014:X2016)
mutate_all
aplica a(s) função(ões) dentro funs
para as colunas especificadas
Eu fiz isso sequencialmente, uma função de cada vez (se você usar várias funções dentro funs
então você cria colunas adicionais desnecessárias)
"Pré-processar" em R:
lines <- "www, rrr, 1,234, ttt \n rrr,zzz, 1,234,567,987, rrr"
Pode usar readLines
com um textConnection
.Em seguida, remova apenas as vírgulas que estão entre os dígitos:
gsub("([0-9]+)\\,([0-9])", "\\1\\2", lines)
## [1] "www, rrr, 1234, ttt \n rrr,zzz, 1234567987, rrr"
Também é útil saber, mas não diretamente relevante para esta questão, que vírgulas como separadores decimais podem ser tratadas por read.csv2 (automagicamente) ou read.table (com configuração do parâmetro 'dec').
Editar:Mais tarde descobri como usar colClasses projetando uma nova classe.Ver:
Como carregar df com separador 1000 em R como classe numérica?
Se o número for separado por "". e decimais por "," (1.200.000,00) na chamada gsub
você deve set fixed=TRUE as.numeric(gsub(".","",y,fixed=TRUE))
Eu acho que o pré -processamento é o caminho a percorrer. Você poderia usar Notepad ++ que tem uma opção de substituição de expressão regular.
Por exemplo, se o seu arquivo era assim:
"1,234","123","1,234"
"234","123","1,234"
123,456,789
Então, você pode usar a expressão regular "([0-9]+),([0-9]+)"
e substitua -o por \1\2
1234,"123",1234
"234","123",1234
123,456,789
Então você pode usar x <- read.csv(file="x.csv",header=FALSE)
para ler o arquivo.
Uma maneira muito conveniente é readr::read_delim
-família. Tomando o exemplo daqui: Importando CSV com vários separadores em R Você pode fazer isso da seguinte maneira:
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 = ",")
O que resulta no resultado esperado:
# 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
Usando a função read_delim, que faz parte de leitura Biblioteca, você pode especificar parâmetro adicional:
locale = locale(decimal_mark = ",")
read_delim("filetoread.csv", ';", locale = locale(decimal_mark = ","))
*Semicolon na segunda linha significa que read_delim lerá valores separados do CSV Semicolon.
Isso ajudará a ler todos os números com uma vírgula como números adequados.
Cumprimentos
Mateusz Kania
Também podemos usar readr::parse_number
, as colunas devem ser caracteres.Se quisermos aplicá-lo a múltiplas colunas, podemos percorrer as colunas usando 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 use mutate_at
de dplyr
para aplicá-lo a variáveis específicas.
library(dplyr)
df %>% mutate_at(2:3, readr::parse_number)
#Or
df %>% mutate_at(vars(b:c), readr::parse_number)
dados
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)