Como ler dados quando alguns números contêm vírgulas como separador de milhar?

Eu tenho um arquivo csv onde alguns dos valores numéricos são expressos como seqüências de caracteres com vírgulas como separador de milhar, por exemplo, "1,513" vez de 1513 . Qual é a maneira mais simples de ler os dados em R?

Eu posso usar read.csv(..., colClasses="character") , mas então eu tenho que remover as vírgulas dos elementos relevantes antes de converter essas colunas para numéricas, e não consigo encontrar uma maneira legal de fazer isso .

Não tenho certeza sobre como ter o read.csv interpretando-o corretamente, mas você pode usar o gsub para replace "," por "" e, em seguida, converter a cadeia para numeric usando as.numeric :

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

Isso também foi respondido anteriormente no R-Help (e no Q2 aqui ).

Como alternativa, você pode pré-processar o arquivo, por exemplo, com sed no unix.

Você pode ter read.table ou read.csv fazer essa conversão para você semi-automaticamente. Primeiro crie uma nova definição de class, crie uma function de conversão e defina-a como um método “as” usando a function setAs da seguinte forma:

 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')) 

Eu quero usar R em vez de pré-processar os dados, pois isso facilita quando os dados são revisados. Seguindo a sugestão de Shane de usar o gsub , acho que isso é o mais legal possível:

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

Esta pergunta é de vários anos, mas me deparei com isso, o que significa que talvez outros o façam.

A biblioteca / pacote readr possui alguns resources interessantes. Uma delas é uma boa maneira de interpretar colunas “confusas”, como essas.

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

Isso produz

Fonte: frame 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ê tem que pré-processar, como o comentário acima sobre o sed , ou você precisa processar durante a leitura . Muitas vezes, se você tentar consertar as coisas depois do fato, existem algumas suposições perigosas que são difíceis de encontrar. (É por isso que arquivos simples são tão ruins em primeiro lugar.)

Por exemplo, se eu não tivesse marcado os col_types , eu teria conseguido isto:

 > 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 o suficiente e a maioria dos elementos iniciais 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 tal forma 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. 

“Pré-processamento” em R:

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

Pode usar readLines em um textConnection . Em seguida, remova apenas as vírgulas 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 essa questão, que vírgulas como separadores decimais podem ser manipuladas por read.csv2 (automagicamente) ou read.table (com configuração do parâmetro 'dec').

Edit: Mais tarde eu descobri como usar colClasses, projetando uma nova class. Vejo:

Como carregar df com 1000 separador em R como class numérica?

uma solução mutate_each usando mutate_each e pipes

digamos que você tenha 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 variables ​​de ano X2014-X2016 e convertê-las em numéricas. Além disso, digamos que o X2014-X2016 seja lido como fatores (padrão)

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

mutate_each aplica a (s) function (ões) dentro de funs às colunas especificadas

Eu fiz isso sequencialmente, uma function de cada vez (se você usar várias funções dentro de funs então você cria colunas adicionais desnecessárias)

Se o número for separado por “.” e decimais por “,” (1.200.000,00) ao chamar 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 o Notepad ++, que tem uma opção de substituição de expressão regular.

Por exemplo, se o seu arquivo fosse assim:

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

Então, você poderia usar a expressão regular "([0-9]+),([0-9]+)" e substituí-la por \1\2

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

Então você poderia usar x < - read.csv(file="x.csv",header=FALSE) para ler o arquivo.

Uma maneira muito conveniente é readr::read_delim . Tomando o exemplo a partir daqui: Importando o csv com vários separadores para o 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 = ",") 

Que resulta no resultado esperado:

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

Outra solução

  y < - c("1,200","20,000","100","12,111") as.numeric(unlist(lapply( strsplit(y,","),paste, collapse=""))) 

Será consideravelmente mais lento que o gsub .

Não é tão complicado, tente isto: y < - as.numérico (gsub (",", "", as.character (y))) e se for apenas uma das colunas, você pode subdividir com y $ 2 como mostrado y $ 2 <- as.numeric (gsub (",", "", as.character (y $ 2)))

Usando a function read_delim, que faz parte da biblioteca readr , você pode especificar o parâmetro adicional:

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

* Ponto e vírgula na segunda linha significa que read_delim irá ler valores separados por ponto e vírgula csv.

Isso ajudará a ler todos os números com uma vírgula como números adequados.

Saudações

Mateusz Kania